Motivazione dello studio di Mehr, Song e Spelke (2016)

Mehr, Song e Spelke (2016) discutono i significati sociali della musica in età evolutiva. Secondo questi ricercatori, la musica è capace di trasmettere significati sociali anche nel caso di bambini molto piccoli. Per valutare questa ipotesi, Mehr et al. (2016) esaminano un campione di 32 bambini di età media pari a 5.6 mesi (SD = 0.31, gamma di variazione: 5.1–6.1). Nel primo esperimento, Mehr e al. si chiedono se la familiarità con una melodia possa modulare la preferenza sociale, ovvero i tempi di fissazione dello sguardo (looking-time) che i bambini dirigono verso un individuo adulto sconosciuto che, cantando, produce una melodia familiare oppure non familiare.

Metodo

Nella prima fase dell’esperimento, ai genitori dei bambini veniva chiesto di imparare una nuova ninna-nanna e di ripeterla spesso al figlio/a. Nella fase test dell’esperimento, ai bambini venivano presentati due video, uno di fianco all’altro. Uno dei due video faceva vedere uno sconosciuto che cantava la melodia che, in precedenza, i genitori avevano presentato ai bambini; l’altro video faceva vedere un altro sconosciuto che cantava una ninna-nanna non conosciuta ai bambini. La variabile dipendente era il tempo di fissazione dello sguardo del bambino.

Nel pre-test, ai bambini venivano mostrati gli stessi due adulti utilizzati nella fase test; in questo caso, però, gli attori si limitavano a sorridere.

Risultati

Mediante una prima analisi statistica (relativa ai dati del pre-test) i ricercatori si sono chiesti se i bambini preferissero uno dei due sconosciuti, quando non cantavano. In una seconda analisi statistica, i ricercatori si sono chiesti se i bambini dimostrano una preferenza per lo sconosciuto che canta la ninna-nanna familiare, piuttosto che per lo sconosciuto che canta la ninna-nanna non familiare – ciò dovrebbe corrispondere a tempi di fissazione maggiri per il primo volto rispetto al secondo.

L’analisi statistica eseguita dagli autori è un test \(t\) di Student. L’articolo di Mehr et al. (2016) riporta un valore della statistica test pari a \(t_{31} = 2.96\), un \(p\)-valore di 0.06 e un intervallo di confidenza al 95% pari a [0.529, 0.658]. La dimensione dell’effetto, misurata con il \(d\) di Cohen, è pari a 0.52.

Conclusioni

Mehr e al. (2016) riportano che i bambini di cinque mesi dirigono in modo preferenziale la propria attenzione verso un adulto sconosciuto che canta una melodia familiare piuttosto che verso un adulto sconosciuto che canta una melodia simile, ma sconosciuta. Questi risultati sono stati trovati quando la familiarizzazione con la ninna-nanna target veniva creata mediante l’interazione tra il bambino e un adulto che faceva parte dell’ambiente domestico. L’attenzione dei bambini, invece, non veniva modulata dalla familiarità con la melodia nel caso in cui la melodia in questione fosse stata presentata in precedenza al bambino in un modo diverso, ovvero essendo prodotta da un giocattolo, o da un adulto che il bambino conosceva poco. In base a tali risultati, Mehr e al. (2016) concludono che le melodie prodotte nell’ambiente domestico, nell’interazione tra i bambini e gli adulti, sono dotate di un particolare significato sociale per i bambini.

Scopo del presente progetto

L’analisi dei dati descritta qui di seguito ha lo scopo di replicare alcuni dei risultati riportati da Mehr et al. (2016) utilizzando i dati resi disponibili dagli autori. Le stesse analisi statistiche verranno eseguite usando due metodi diversi: l’approccio frequentista (quello usato nell’articolo) e l’approccio bayesiano.

Analisi dei dati

Per replicare i risultati riportati da Mehr et al. (2016), iniziamo a leggere in R i dati contenuti nel file MehrSongSpelke_exp_1.csv. Questo risultato si ottiene utilizzando la funzione import() contenuta nel pacchetto rio. Utilizziamo anche le funzionalità dei pacchetti tidyverse per manipolare i dati e creare grafici.

Dopo avere cambiato la cartella di lavoro in RStudio, carichiamo i pacchetti che verranno utilizzati mediante le seguenti istruzioni:

suppressPackageStartupMessages({
  library("here")
  library("tidyverse")
  library("patchwork")
  library("bayesplot")
})  

theme_set(bayesplot::theme_default(base_size = 12))
bayesplot::color_scheme_set("brightblue") 

options(
  digits = 3,
  width = 68,
  str = strOptions(strict.width = "cut"),
  crayon.enabled = TRUE
)

knitr::opts_chunk$set(
  comment = "#>",
  collapse = TRUE,
  message = FALSE,
  warning = FALSE,
  error = FALSE,
  width = 68,
  fig.align = "center",
  fig.width = 6,
  fig.asp = 0.618, # 1 / phi
  fig.show = "hold",
  dpi = 300,
  fig.pos = "h",
  cache.extra = knitr::rand_seed,
  tidy.opts = list(width.cutoff = 70),
  tidy = "styler"
)
mehr <- rio::import("MehrSongSpelke_exp_1.csv")

I nomi delle colonne dell’oggetto mehr vengono restituiti usando la funzione names() che prende come argomento il nome del data.frame:

names(mehr)

Consideriamo la variabile exp1:

unique(mehr$exp1)
#> [1] 1 0

Quando exp1 assume il valore 1, i dati appartengono al primo esperimento, quello di interesse qui. Per selezionare i dati del primo esperimento usiamo la funzione filter():

df_exp1 <- mehr %>% 
  dplyr::filter(exp1 == 1)

L’istruzione precedente dice che l’oggetto mehr (che è un DataFrame) viene passato alla funzione filter() contenuta nel pacchetto dplyr. L’argomento passato a filter() istruisce R a selezionare solo le righe del data.frame mehr nelle quali la colonna exp ha valore 1. Il sottoinsieme delle righe selezionate corrispone alle osservazioni che fanno parte del primo esperimento. L’operatore di attribuzione <- assegna al risultato che abbiamo ottenuto (ovvero, ai dati del primo esperimento) il nome df_exp1.

La variabile Test_Proportion_Gaze_to_Singer corrisponde al tempo di fissazione dello sguardo (espresso nei termini di una proporzione). Costruiamo un istogramma:

tibble(y = df_exp1$Test_Proportion_Gaze_to_Singer) %>% 
ggplot(aes(y)) +
  geom_histogram(
    aes(y = ..density..)
  )

Più utile è una stima della densità della frequenza dei dati:

tibble(y = df_exp1$Test_Proportion_Gaze_to_Singer) %>% 
ggplot(aes(y)) +
  geom_density()

Media e deviazione standard delle proporzioni di tempo trascorso a fissare il volto target (sconosciuto che canta la ninna-nanna familiare) si ottengono nel modo seguente:

df_exp1 %>% 
  summarise(
    p = mean(Test_Proportion_Gaze_to_Singer),
    std = sd(Test_Proportion_Gaze_to_Singer)
  )
#>       p   std
#> 1 0.593 0.179

Approccio frequentista

Test \(t\) di Student per un solo campione

Utilizziamo ora l’approccio frequentista per fare inferenza su \(\mu\), ovvero sulla proporzione media del tempo di fissazione rivolto allo sconosciuto target, piuttosto che verso lo sconosciuto che canta una ninna-nanna ignota al bambino.

L’ipotesi nulla è

\[ H_0: \mu = 0.5. \]

Se non vi è alcuna preferenza, la variabile Test_Proportion_Gaze_to_Singer dovrebbe assumere il valore 0.5. Se invece i bambini preferiscono la melodia familiare, il valore medio di Test_Proportion_Gaze_to_Singer dovrebbe essere maggiore di 0.5; se i bambini preferiscono la melodia sconosciuta, il valore medio di Test_Proportion_Gaze_to_Singer dovrebbe essere minore di 0.5.

Iniziamo ad esaminare la distribuzione dei dati. Usiamo il diagramma quantile-quantile per verificare l’ipotesi di gaussianità (necessaria per eseguire il test statistico riportato dagli autori):

tibble(y = df_exp1$Test_Proportion_Gaze_to_Singer) %>% 
  ggplot(aes(sample = y)) +
  stat_qq() + 
  stat_qq_line()

Dato che l’assunzione di gaussianità è ragionevole, procediamo eseguendo il test \(t\) di Student. La proporzione del looking-time diretta allo sconosciuto che canta la melodia familiare è

m <- mean(df_exp1$Test_Proportion_Gaze_to_Singer)
m
#> [1] 0.593

pari a 0.59. Abiamo trovato tale valore usando la funzione mean() che prende, come argomento, il vettore che contiene la proporzione del looking-time diretta allo sconosciuto che canta la melodia familiare per ciascun bambino nel primo esperimento. Utilizziamo la sintassi $ per estrarre dal DataFrame df_exp1 la colonna di dati Test_Proportion_Gaze_to_Singer.

L’errore standard della media è

\[ \sigma_{\bar{y}} = \frac{\sigma}{\sqrt{n}} \] ovvero

se <- sd(df_exp1$Test_Proportion_Gaze_to_Singer) / sqrt(length(df_exp1$Test_Proportion_Gaze_to_Singer))
se
#> [1] 0.0316

La funzione length() ritorna il numero di elementi di un vettore ovvero, nel nostro caso, l’ampiezza del campione.

Applichiamo ora la formula per il calcolo della statistica T, ovvero

\[ T = \frac{\bar{y} - \mu_0}{\hat{\sigma}_{\bar{y}}} = \frac{0.59 - 0.50}{0.032} = 2.96 \]

ovvero

T <- (m - 0.5) / se
T
#> [1] 2.96

I gradi di libertà sono:

dof <- length(df_exp1$Test_Proportion_Gaze_to_Singer) - 1
dof
#> [1] 31

Per un test bidirezionale, il \(p\)-valore diventa

round(2 * (1 - pt(T, dof)), 3)
#> [1] 0.006

Nell’istruzione precedente abbiamo calcolato l’area sottesa alla ditribuzione \(t_{31}\) nell’intervallo \([2.960, \infty]\) e l’abbiamo moltiplicata per 2. Per trovare l’area nell’intervallo \([2.960, \infty]\), abbiamo calcolato il valore della funzione di ripartizione in corrispondenza del valore 2.960 (ovvero l’area nell’intervallo \([-\infty, 2.960]\)) e abbiamo sottratto tale valore da 1.0.

Gli stessi risultati, che coincidono con quelli trovati sopra e con quelli riportati dagli autori, si possono facilmente ottenere usando la funzione t.test()

t.test(df_exp1$Test_Proportion_Gaze_to_Singer, mu = 0.5)
#> 
#>  One Sample t-test
#> 
#> data:  df_exp1$Test_Proportion_Gaze_to_Singer
#> t = 3, df = 31, p-value = 0.006
#> alternative hypothesis: true mean is not equal to 0.5
#> 95 percent confidence interval:
#>  0.529 0.658
#> sample estimates:
#> mean of x 
#>     0.593

L’intervallo di confidenza al 95% si calcola come

\[ \text{stima del parametro} \pm t \times \text{errore standard} \] Nel caso presente, abbiamo:

round(m + c(-1, 1) * qt(0.975, dof) * se, 3)
#> [1] 0.529 0.658

Tale risultato riproduce quello riportato da Mehr et al. (2016).

Una stima della dimensione dell’effetto si ottiene come il rapporto tra la differenza tra le medie (in questo caso, proporzioni) e la relativa deviazione standard:

round(
  (m - 0.5) / sd(df_exp1$Test_Proportion_Gaze_to_Singer),
  3
)
#> [1] 0.523

Anche questo risultato coincide con il valore riportato dagli autori.

Analisi Bayesiana

Ci poniamo ora il problema di ripetere le analisi statiche precedenti utilizzando l’approccio bayesiano. Carichiamo i pacchetti necessari:

suppressPackageStartupMessages({
  library("brms")
  library("rstan")
  library("cmdstanr")
  library("posterior")
  library("loo")
})

rstan_options(auto_write = TRUE) # avoid recompilation of models
options(mc.cores = parallel::detectCores()) # parallelize across all CPUs
Sys.setenv(LOCAL_CPPFLAGS = "-march=native") # improve execution time
rstan_options(auto_write = TRUE) # avoid recompilation of models
options(mc.cores = parallel::detectCores()) # parallelize across all CPUs
Sys.setenv(LOCAL_CPPFLAGS = "-march=native") # improve execution time

I dati sono i seguenti:

y <- sort(df_exp1$Test_Proportion_Gaze_to_Singer)
y
#>  [1] 0.263 0.282 0.366 0.418 0.419 0.437 0.460 0.462 0.473 0.499
#> [11] 0.500 0.508 0.508 0.531 0.542 0.542 0.572 0.586 0.601 0.603
#> [21] 0.624 0.683 0.700 0.724 0.760 0.763 0.777 0.789 0.811 0.900
#> [31] 0.938 0.951

Considereremo \(y\) (così come hanno fatto gli autori) come una variabile continua per la quale è sensato assumere un meccanismo generatore dei dati gaussiano di media e deviazione standard ignote. L’inferenza riguarda il parametro \(\mu\) di tale distribuzione gaussiana.

Funzione brm()

Utilizzando delle distribuzioni a priori per i parametri debolmente informative, facciamo inferenza utilizzando la funzione brm() del pacchetto brms:

fit <- brm(
  data = df_exp1, 
  family = gaussian(),
  Test_Proportion_Gaze_to_Singer ~ 1,
  prior = c(
    prior(normal(0, 2.0), class = Intercept),
    prior(cauchy(0, 2.0), class = sigma)
  ),
  iter = 4000, 
  refresh = 0, 
  chains = 4,
  backend = "cmdstanr"
)
#> Running MCMC with 4 chains, at most 8 in parallel...
#> 
#> Chain 1 finished in 0.1 seconds.
#> Chain 2 finished in 0.0 seconds.
#> Chain 3 finished in 0.1 seconds.
#> Chain 4 finished in 0.0 seconds.
#> 
#> All 4 chains finished successfully.
#> Mean chain execution time: 0.1 seconds.
#> Total execution time: 0.3 seconds.

Le stime a posteriori dei parametri si recuperano nel modo seguente:

fixef(fit)
#>           Estimate Est.Error  Q2.5 Q97.5
#> Intercept    0.593    0.0334 0.527 0.657

Nell’output, Estimate corrisponde alla stima della media a posteriori, mentre Q2.5 e Q97.5 forniscono gli estremi dell’intervallo di credibilità al 95%. I risultati sono simili a quelli riportati dagli autori.

Modello in linguaggio Stan

Ripetiamo ora l’analisi precedente utilizzano un modello scritto in linguaggio Stan. Il modello riportato di seguito verrà salvato nella cartella code con il nome normalmodel.stan:

modelString = "
data {
  int<lower=0> N;
  vector[N] y;
}
parameters {
  real mu;
  real<lower=0> sigma;
}
model {
  mu ~ normal(0.5, 0.5);
  sigma ~ cauchy(0, 1);
  y ~ normal(mu, sigma);
}
"
writeLines(modelString, con = "code/normalmodel.stan")

Sistemiamo i dati nel formato appropriato per Stan:

data_list <- list(
  N = length(df_exp1$Test_Proportion_Gaze_to_Singer),
  y = df_exp1$Test_Proportion_Gaze_to_Singer
)
data_list
#> $N
#> [1] 32
#> 
#> $y
#>  [1] 0.603 0.683 0.724 0.282 0.499 0.951 0.418 0.938 0.500 0.586
#> [11] 0.473 0.508 0.811 0.572 0.777 0.263 0.508 0.437 0.542 0.601
#> [21] 0.419 0.789 0.760 0.624 0.366 0.462 0.900 0.531 0.542 0.700
#> [31] 0.763 0.460

Leggiamo il file in cui abbiamo salvato il codice Stan

file <- file.path("code", "normalmodel.stan")

compiliamo il modello

mod <- cmdstan_model(file)

ed eseguiamo il campionamento MCMC:

fit <- mod$sample(
  data = data_list,
  iter_sampling = 4000L,
  iter_warmup = 2000L,
  seed = 123,
  chains = 4L,
  parallel_chains = 2L,
  refresh = 0,
  thin = 1
)

La convergenza e il “mixing” del campionamanto MCMC possono essere controllate mediante il trace plot che mostra l’andamento delle simulazioni e ci dice se stiamo effettivamente utilizzando una distribuzione limite:

Convertiamo l’oggetto fit in formato stanfit,

stanfit <- rstan::read_stan_csv(fit$output_files())

Esaminiamo i trace-plot:

stanfit %>% 
  mcmc_trace(pars = c("mu", "sigma"), size = 0.1)

La stima della distribuzione a posteriori per \(\mu\) per ciascuna delle quattro catene usate può essere rappresentata graficamente nel modo seguente:

mcmc_dens_overlay(stanfit, pars = "mu") + 
  ylab("density")

Esaminiamo la statistica \(\hat{R}\):

bayesplot::rhat(stanfit, pars = c("mu", "sigma"))
#>    mu sigma 
#>     1     1

Utilizzando l’oggetto stanfit, possiamo recuperare la statistica di Geweke nel modo seguente:

fit_mcmc <- As.mcmc.list(
  stanfit,
  pars = c("mu", "sigma")
)
coda::geweke.diag(fit_mcmc, frac1 = .1, frac2 = .5) 
#> [[1]]
#> 
#> Fraction in 1st window = 0.1
#> Fraction in 2nd window = 0.5 
#> 
#>    mu sigma 
#>  1.21  1.60 
#> 
#> 
#> [[2]]
#> 
#> Fraction in 1st window = 0.1
#> Fraction in 2nd window = 0.5 
#> 
#>    mu sigma 
#> 0.631 0.874 
#> 
#> 
#> [[3]]
#> 
#> Fraction in 1st window = 0.1
#> Fraction in 2nd window = 0.5 
#> 
#>     mu  sigma 
#> -0.271 -0.589 
#> 
#> 
#> [[4]]
#> 
#> Fraction in 1st window = 0.1
#> Fraction in 2nd window = 0.5 
#> 
#>     mu  sigma 
#> -0.276  0.180

La statistica di Geweke è uguale a zero quando le medie delle due porzioni della catena di Markov sono uguali. Valori maggiori di \(\mid 2 \mid\) suggeriscono che la catena non ha ancora raggiunto una distribuzione stazionaria.

Le stime a posteriori dei parametri si ottengono con

s <- summary(
  stanfit, 
  c("mu", "sigma"), 
  probs = c(0.025, 0.50, 0.975),
  use_cache = TRUE
  )
s$summary  # all chaines merged
#>        mean  se_mean     sd  2.5%   50% 97.5% n_eff Rhat
#> mu    0.594 0.000309 0.0332 0.529 0.594 0.659 11504    1
#> sigma 0.186 0.000235 0.0251 0.144 0.183 0.241 11427    1

I risultati replicano quelli ottenuti in precedenza.

Modifichiamo ora il modello inserendo una distribuzione a priori più sensata per il parametro \(\mu\). Essendo una proporzione, deve essere un numero compreso tra 0 e 1. Pertanto, quale distribuzione a priori, è sensato usare una distribuzione Beta. Utilizzeremo qui una Beta(2,2), ovvero una distribuzione a priori debolmente informativa.

modelString = "
data {
  int<lower=0> N;
  vector[N] y;
}
parameters {
  real mu;
  real<lower=0> sigma;
}
model {
  mu ~ beta(2, 2);
  sigma ~ cauchy(0, 1);
  y ~ normal(mu, sigma);
}
"
writeLines(modelString, con = "code/normalmodel2.stan")

Leggiamo il file in cui abbiamo salvato il codice Stan

file2 <- file.path("code", "normalmodel2.stan")

compiliamo il modello

mod2 <- cmdstan_model(file2)

ed eseguiamo il campionamento MCMC:

fit2 <- mod2$sample(
  data = data_list,
  iter_sampling = 4000L,
  iter_warmup = 2000L,
  seed = 123,
  chains = 4L,
  parallel_chains = 2L,
  refresh = 0,
  thin = 1
)

Troviamo le stime a posteriori dei parametri:

stanfit2 <- rstan::read_stan_csv(fit2$output_files())

s <- summary(
  stanfit2, 
  c("mu", "sigma"), 
  probs = c(0.025, 0.50, 0.975),
  use_cache = TRUE
  )
s$summary  # all chaines merged
#>        mean  se_mean     sd  2.5%   50% 97.5% n_eff Rhat
#> mu    0.593 0.000293 0.0334 0.527 0.594 0.659 13016    1
#> sigma 0.186 0.000227 0.0250 0.145 0.183 0.242 12073    1

I risultati sono quasi identici a quelli trovati in precedenza.

Possiamo dunque concludere, con un grado di certezza soggettiva del 95%, che siamo sicuri che la proporzione del tempo complessivo di fissazione dello sguardo verso lo sconosciuto che cantava la melodia familiare (piuttosto che verso lo sconosciuto che cantava una ninn-nanna ignota), è compresa nell’intervallo [0.527, 0.659].

Confronto tra due gruppi

Approccio frequentista (test \(t\) di Student per campioni appaiati)

In una diversa analisi statistica, Mehr e al. (2016) hanno confrontato il tempo di fissazione dello sguardo diretto verso lo sconosciuto che sorride soltanto e verso lo sconosciuto che canta la ninna-nanna familiare. Ci dovremmo aspettare un tempo di fissazione maggiore nel secondo caso rispetto al primo.

La distribuzione dei tempi di fissazione dello sguardo nelle due condizioni è presentata nel pannello a della Figura 2 del loro articolo. Riproduciamo qui sotto la figura. I tempi di fissazione dello sguardo nelle condizioni baseline e test corrispondono, rispettivamente, alle variabili Baseline_Proportion_Gaze_to_Singer e Test_Proportion_Gaze_to_Singer.

Per replicare la Figura 2a riportata nell’articolo dobbiamo sistemare i dati nel formato ``long’’, ovvero nel formato in cui a ciascuna colonna del DataFrame corrisponde una variabile. Nel caso presente, possiamo creare una variabile chiamata condizione, con modalità baseline e test, e una seconda variabile, y, che corrisponde ai tempi di fissazione dello sguardo. Per creare un DataFrame che contiene queste due variabili, procediamo come segue.

condizione <- factor(
  rep(
    c("baseline", "test"), 
    each = length(df_exp1$Baseline_Proportion_Gaze_to_Singer)
    )
  )
y <- c(df_exp1$Baseline_Proportion_Gaze_to_Singer, df_exp1$Test_Proportion_Gaze_to_Singer)
df2 <- data.frame(condizione, y)
head(df2)
#>   condizione     y
#> 1   baseline 0.437
#> 2   baseline 0.413
#> 3   baseline 0.754
#> 4   baseline 0.439
#> 5   baseline 0.475
#> 6   baseline 0.871
dim(df2)
#> [1] 64  2

Il diagramma a scatola (simile a quello riportato nell’articolo) si crea con le seguenti istruzioni:

p <- df2 %>%
  ggplot(aes(x = condizione, y = y, fill = condizione)) +
  geom_boxplot(alpha = 0.7) +
  scale_y_continuous(
    name = "Proporzione di fissazioni verso il \ncantante di canzone familiare"
  ) +
  scale_x_discrete(name = "Condizione") +
  theme(legend.position = "none") +
  geom_hline(yintercept = 0.5, linetype = "dashed") +
  stat_summary(
    fun.y = mean, colour = "darkred", geom = "point",
    shape = 18, size = 6
  )
p

Una rappresentazione più efficace dei dati si ottiene riportando, per ciascuna condizione, tutte le singole osservazioni, insieme alla mediana di ciascun gruppo:

 mehr_summary <- df2 %>%
  group_by(condizione) %>%
  summarize(
    lt_mean = mean(y),
    lt_sd = sd(y),
    lt_median = median(y)
  ) %>%
  ungroup()
df2 %>%
  ggplot(
    aes(x = condizione, y = y, color = condizione)
  ) +
  ggforce::geom_sina(aes(color = condizione, size = 3, alpha = .5)) +
  geom_errorbar(
    aes(y = lt_median, ymin = lt_median, ymax = lt_median),
    data = mehr_summary, width = 0.5, size = 3
  ) +
  labs(
    x = "",
    y = "Proporzione di fissazioni verso il \ncantante di canzone familiare"
  ) +
  theme(legend.position = "none") +
  scale_colour_grey(start = 0.7, end = 0)

Un confronto tra queste due condizioni viene effettuato con un test \(t\) di Student per campioni appaiati. Ovvero

diff <- df_exp1$Test_Proportion_Gaze_to_Singer - df_exp1$Baseline_Proportion_Gaze_to_Singer
diff
#>  [1]  0.16561  0.27049 -0.03035 -0.15722  0.02390  0.08002  0.18104
#>  [8]  0.17894  0.08367 -0.21324  0.09395 -0.18951  0.21778 -0.04311
#> [15]  0.16254 -0.05399  0.19752 -0.06739  0.07277  0.09682 -0.14536
#> [22]  0.53284  0.06011  0.24154 -0.00545  0.17707  0.13171  0.05731
#> [29] -0.27932  0.11023  0.34093  0.02479

Verifichiamo la gaussianità dei dati:

tibble(y = diff) %>% 
  ggplot(aes(sample = y)) +
  stat_qq() + 
  stat_qq_line()

La media delle differenze è:

m <- mean(diff)
m
#> [1] 0.0724

L’errore standard delle differenze è:

se <- sd(diff) / sqrt(length(diff))
se
#> [1] 0.03

La statistica \(T\) è:

T <- (m - 0) / se
T
#> [1] 2.42

I gradi di libertà sono:

nu <- length(diff) - 1
nu
#> [1] 31

Il p-valore è:

2 * (1 - pt(T, nu))
#> [1] 0.0218

Usando t.test() otteniamo:

t.test(diff, mu = 0)
#> 
#>  One Sample t-test
#> 
#> data:  diff
#> t = 2, df = 31, p-value = 0.02
#> alternative hypothesis: true mean is not equal to 0
#> 95 percent confidence interval:
#>  0.0113 0.1335
#> sample estimates:
#> mean of x 
#>    0.0724

Questi risultati replicano i valori riportati dagli autori: \(t_{31}\) = 2.42, \(p\) = 0.22.

L’intervallo di confidenza è

mean(diff) + c(-1, 1) * qt(.975, nu) * se
#> [1] 0.0113 0.1335

La dimensione dell’effetto è

d <- mean(diff) / sd(diff)
d
#> [1] 0.427

Le stime dell’intervallo di confidenza e della dimensione dell’effetto coincidono con i valori riportati da Mehr e al. (2016).

Analisi bayesiana

Dato che, nel caso di campioni appaiati, abbiamo un unico valore della varibile dipendente per ciascuna “coppia”, l’analisi statistica è sostanzialmente identica a quella già descritta sopra. In questo caso, la variabile dipendente è chiamata diff.

data2_list <- list(
  N = length(diff),
  y = diff
)
data2_list
#> $N
#> [1] 32
#> 
#> $y
#>  [1]  0.16561  0.27049 -0.03035 -0.15722  0.02390  0.08002  0.18104
#>  [8]  0.17894  0.08367 -0.21324  0.09395 -0.18951  0.21778 -0.04311
#> [15]  0.16254 -0.05399  0.19752 -0.06739  0.07277  0.09682 -0.14536
#> [22]  0.53284  0.06011  0.24154 -0.00545  0.17707  0.13171  0.05731
#> [29] -0.27932  0.11023  0.34093  0.02479

Usiamo nuovamente il modello normalmodel2.stan che abbiamo già compilato in precedenza ed eseguiamo il campionamento MCMC:

fit3 <- mod2$sample(
  data = data2_list,
  iter_sampling = 4000L,
  iter_warmup = 2000L,
  seed = 123,
  chains = 4L,
  parallel_chains = 2L,
  refresh = 0,
  thin = 1
)

Le stime a posteriori dei parametri si ottengono con:

stanfit3 <- rstan::read_stan_csv(fit3$output_files())
s <- summary(
  stanfit3, 
  c("mu", "sigma"), 
  probs = c(0.025, 0.50, 0.975),
  use_cache = TRUE
  )
s$summary  # all chaines merged
#>        mean  se_mean     sd   2.5%   50% 97.5% n_eff Rhat
#> mu    0.085 0.000281 0.0286 0.0322 0.084 0.146 10406    1
#> sigma 0.176 0.000233 0.0238 0.1374 0.174 0.231 10392    1

I risultati sono molto simili ai precedenti.

Dall’output precedente possiamo ottenere una stima della dimensione dell’effetto:

s$summary[1, 1] /   s$summary[2, 1]
#> [1] 0.482

Anche in questo caso, il risultato è simile a quello ottenuto sopra.

Conclusioni

Utilizzando i dati grezzi messi a disposizione dagli autori siamo stati in grado di replicare i risultati riportati dall’articolo di Mehr e al. (2016). In questa relazione ci siamo focalizzati su due problemi: l’inferenza su una media e l’inferenza su due medie nel caso di dati appaiati. Nel caso presente, i risultati dell’analisi bayesiana sono praticamente identici a quelli prodotti dall’approccio frequentista, se vengono usate distribuzioni a priori debolmente informative. Utilizzando ggplot() siamo anche stati in grado di replicare una delle figure riportate nell’articolo di Mehr e al. (2016). Abbiamo anche proposto una nuova versione di tale figura che sembra più informativa di quella proposta dagli autori.

Le analisi statistiche descritte da Mehr e al. (2016) sono convincenti: i dati non mostrano anomalie degne di nota e le assunzioni alla base dei test statistici svolti dagli autori – ovvero, la gaussianità dei dati – sono sensate. È dunque sensato concludere che la musica sembra possedere un importante valore sociale anche nel caso di bambini molto piccoli.

Riferimenti bibliografici

Mehr, S. A., Song, L. A., & Spelke, E. S. (2016). For 5-month-old infants, melodies are social. Psychological Science, 27(4), 486-501.

Informazioni sulla sessione di lavoro

sessionInfo()
#> R version 4.1.2 (2021-11-01)
#> Platform: x86_64-apple-darwin17.0 (64-bit)
#> Running under: macOS Big Sur 10.16
#> 
#> Matrix products: default
#> BLAS:   /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRblas.0.dylib
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRlapack.dylib
#> 
#> locale:
#> [1] it_IT.UTF-8/it_IT.UTF-8/it_IT.UTF-8/C/it_IT.UTF-8/it_IT.UTF-8
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods  
#> [7] base     
#> 
#> other attached packages:
#>  [1] loo_2.4.1            posterior_1.2.0      cmdstanr_0.4.0.9000 
#>  [4] rstan_2.21.3         StanHeaders_2.21.0-7 brms_2.16.3         
#>  [7] Rcpp_1.0.8           bayesplot_1.8.1      patchwork_1.1.1     
#> [10] forcats_0.5.1        stringr_1.4.0        dplyr_1.0.7         
#> [13] purrr_0.3.4          readr_2.1.1          tidyr_1.1.4         
#> [16] tibble_3.1.6         ggplot2_3.3.5        tidyverse_1.3.1     
#> [19] here_1.0.1          
#> 
#> loaded via a namespace (and not attached):
#>   [1] readxl_1.3.1         backports_1.4.1      plyr_1.8.6          
#>   [4] igraph_1.2.11        splines_4.1.2        crosstalk_1.2.0     
#>   [7] TH.data_1.1-0        rstantools_2.1.1     inline_0.3.19       
#>  [10] digest_0.6.29        htmltools_0.5.2      rsconnect_0.8.25    
#>  [13] fansi_1.0.2          magrittr_2.0.2       checkmate_2.0.0     
#>  [16] tzdb_0.2.0           openxlsx_4.2.5       modelr_0.1.8        
#>  [19] RcppParallel_5.1.5   matrixStats_0.61.0   R.utils_2.11.0      
#>  [22] sandwich_3.0-1       xts_0.12.1           prettyunits_1.1.1   
#>  [25] colorspace_2.0-2     rvest_1.0.2          haven_2.4.3         
#>  [28] xfun_0.29            callr_3.7.0          crayon_1.4.2        
#>  [31] jsonlite_1.7.3       lme4_1.1-27.1        survival_3.2-13     
#>  [34] zoo_1.8-9            glue_1.6.1           polyclip_1.10-0     
#>  [37] gtable_0.3.0         emmeans_1.7.2        distributional_0.3.0
#>  [40] R.cache_0.15.0       pkgbuild_1.3.1       abind_1.4-5         
#>  [43] scales_1.1.1         mvtnorm_1.1-3        DBI_1.1.2           
#>  [46] miniUI_0.1.1.1       xtable_1.8-4         foreign_0.8-82      
#>  [49] stats4_4.1.2         DT_0.20              htmlwidgets_1.5.4   
#>  [52] httr_1.4.2           threejs_0.3.3        ellipsis_0.3.2      
#>  [55] pkgconfig_2.0.3      R.methodsS3_1.8.1    farver_2.1.0        
#>  [58] sass_0.4.0           dbplyr_2.1.1         utf8_1.2.2          
#>  [61] tidyselect_1.1.1     labeling_0.4.2       rlang_1.0.0.9000    
#>  [64] reshape2_1.4.4       later_1.3.0          munsell_0.5.0       
#>  [67] cellranger_1.1.0     tools_4.1.2          cli_3.1.1           
#>  [70] generics_0.1.1       broom_0.7.12         ggridges_0.5.3      
#>  [73] evaluate_0.14        fastmap_1.1.0        yaml_2.2.2          
#>  [76] processx_3.5.2       knitr_1.37           fs_1.5.2            
#>  [79] zip_2.2.0            nlme_3.1-155         projpred_2.0.2      
#>  [82] mime_0.12            R.oo_1.24.0          xml2_1.3.3          
#>  [85] compiler_4.1.2       shinythemes_1.2.0    rstudioapi_0.13     
#>  [88] gamm4_0.2-6          curl_4.3.2           reprex_2.0.1        
#>  [91] tweenr_1.0.2         bslib_0.3.1          stringi_1.7.6       
#>  [94] highr_0.9            ps_1.6.0             Brobdingnag_1.2-6   
#>  [97] lattice_0.20-45      Matrix_1.4-0         nloptr_2.0.0        
#> [100] styler_1.6.2         markdown_1.1         shinyjs_2.1.0       
#> [103] tensorA_0.36.2       vctrs_0.3.8          pillar_1.6.5        
#> [106] lifecycle_1.0.1      jquerylib_0.1.4      bridgesampling_1.1-2
#> [109] estimability_1.3     data.table_1.14.2    httpuv_1.6.5        
#> [112] R6_2.5.1             promises_1.2.0.1     gridExtra_2.3       
#> [115] rio_0.5.29           codetools_0.2-18     boot_1.3-28         
#> [118] MASS_7.3-55          colourpicker_1.1.1   gtools_3.9.2        
#> [121] assertthat_0.2.1     rprojroot_2.0.2      withr_2.4.3         
#> [124] shinystan_2.5.0      multcomp_1.4-18      mgcv_1.8-38         
#> [127] parallel_4.1.2       hms_1.1.1            grid_4.1.2          
#> [130] minqa_1.2.4          coda_0.19-4          rmarkdown_2.11      
#> [133] ggforce_0.3.3        shiny_1.7.1          lubridate_1.8.0     
#> [136] base64enc_0.1-3      dygraphs_1.1.1.6
LS0tCnRpdGxlOiAiSWwgc2lnbmlmaWNhdG8gc29jaWFsZSBkZWxsYSBtdXNpY2EgaW4gZXTDoCBldm9sdXRpdmEiCnN1YnRpdGxlOiAiTGFib3JhdG9yaW8gZGlkYXR0aWNvOiBlc2VtcGlvIGRpIHJlbGF6aW9uZSIgCmF1dGhvcjogQ29ycmFkbyBDYXVkZWsKZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IHJlYWRhYmxlCiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQoKIyBNb3RpdmF6aW9uZSBkZWxsbyBzdHVkaW8gZGkgTWVociwgU29uZyBlIFNwZWxrZSAoMjAxNikKCk1laHIsIFNvbmcgZSBTcGVsa2UgKDIwMTYpIGRpc2N1dG9ubyBpIHNpZ25pZmljYXRpIHNvY2lhbGkgZGVsbGEgbXVzaWNhIGluIGV0w6AgZXZvbHV0aXZhLiBTZWNvbmRvIHF1ZXN0aSByaWNlcmNhdG9yaSwgbGEgbXVzaWNhIMOoIGNhcGFjZSBkaSB0cmFzbWV0dGVyZSBzaWduaWZpY2F0aSBzb2NpYWxpIGFuY2hlIG5lbCBjYXNvIGRpIGJhbWJpbmkgbW9sdG8gcGljY29saS4gUGVyIHZhbHV0YXJlIHF1ZXN0YSBpcG90ZXNpLCBNZWhyIGV0IGFsLiAoMjAxNikgZXNhbWluYW5vIHVuIGNhbXBpb25lIGRpIDMyIGJhbWJpbmkgZGkgZXTDoCBtZWRpYSBwYXJpIGEgNS42IG1lc2kgKFNEID0gMC4zMSwgZ2FtbWEgZGkgdmFyaWF6aW9uZTogNS4xLS02LjEpLiBOZWwgcHJpbW8gZXNwZXJpbWVudG8sIE1laHIgZSBhbC4gc2kgY2hpZWRvbm8gc2UgbGEgZmFtaWxpYXJpdMOgIGNvbiB1bmEgbWVsb2RpYSBwb3NzYSBtb2R1bGFyZSBsYSBwcmVmZXJlbnphIHNvY2lhbGUsIG92dmVybyBpIHRlbXBpIGRpIGZpc3NhemlvbmUgZGVsbG8gc2d1YXJkbyAoX2xvb2tpbmctdGltZV8pIGNoZSBpIGJhbWJpbmkgZGlyaWdvbm8gdmVyc28gdW4gaW5kaXZpZHVvIGFkdWx0byBzY29ub3NjaXV0byBjaGUsIGNhbnRhbmRvLCBwcm9kdWNlIHVuYSBtZWxvZGlhIGZhbWlsaWFyZSBvcHB1cmUgbm9uIGZhbWlsaWFyZS4KCiMjIE1ldG9kbwoKTmVsbGEgcHJpbWEgZmFzZSBkZWxsJ2VzcGVyaW1lbnRvLCBhaSBnZW5pdG9yaSBkZWkgYmFtYmluaSB2ZW5pdmEgY2hpZXN0byBkaSBpbXBhcmFyZSB1bmEgbnVvdmEgbmlubmEtbmFubmEgZSBkaSByaXBldGVybGEgc3Blc3NvIGFsIGZpZ2xpby9hLiBOZWxsYSBmYXNlIHRlc3QgZGVsbCdlc3BlcmltZW50bywgYWkgYmFtYmluaSB2ZW5pdmFubyBwcmVzZW50YXRpIGR1ZSB2aWRlbywgdW5vIGRpIGZpYW5jbyBhbGwnYWx0cm8uIFVubyBkZWkgZHVlIHZpZGVvIGZhY2V2YSB2ZWRlcmUgdW5vIHNjb25vc2NpdXRvIGNoZSBjYW50YXZhIGxhIG1lbG9kaWEgY2hlLCBpbiBwcmVjZWRlbnphLCBpIGdlbml0b3JpIGF2ZXZhbm8gcHJlc2VudGF0byBhaSBiYW1iaW5pOyBsJ2FsdHJvIHZpZGVvIGZhY2V2YSB2ZWRlcmUgdW4gYWx0cm8gc2Nvbm9zY2l1dG8gY2hlIGNhbnRhdmEgdW5hIG5pbm5hLW5hbm5hIG5vbiBjb25vc2NpdXRhIGFpIGJhbWJpbmkuIExhIHZhcmlhYmlsZSBkaXBlbmRlbnRlIGVyYSBpbCB0ZW1wbyBkaSBmaXNzYXppb25lIGRlbGxvIHNndWFyZG8gZGVsIGJhbWJpbm8uCgpOZWwgcHJlLXRlc3QsIGFpIGJhbWJpbmkgdmVuaXZhbm8gbW9zdHJhdGkgZ2xpIHN0ZXNzaSBkdWUgYWR1bHRpIHV0aWxpenphdGkgbmVsbGEgZmFzZSB0ZXN0OyBpbiBxdWVzdG8gY2FzbywgcGVyw7IsIGdsaSBhdHRvcmkgc2kgbGltaXRhdmFubyBhIHNvcnJpZGVyZS4KCiMjIFJpc3VsdGF0aQoKTWVkaWFudGUgdW5hIHByaW1hIGFuYWxpc2kgc3RhdGlzdGljYSAocmVsYXRpdmEgYWkgZGF0aSBkZWwgcHJlLXRlc3QpIGkgcmljZXJjYXRvcmkgc2kgc29ubyBjaGllc3RpIHNlIGkgYmFtYmluaSBwcmVmZXJpc3Nlcm8gdW5vIGRlaSBkdWUgc2Nvbm9zY2l1dGksIHF1YW5kbyBub24gY2FudGF2YW5vLiBJbiB1bmEgc2Vjb25kYSBhbmFsaXNpIHN0YXRpc3RpY2EsIGkgcmljZXJjYXRvcmkgc2kgc29ubyBjaGllc3RpIHNlIGkgYmFtYmluaSBkaW1vc3RyYW5vIHVuYSBwcmVmZXJlbnphIHBlciBsbyBzY29ub3NjaXV0byBjaGUgY2FudGEgbGEgbmlubmEtbmFubmEgZmFtaWxpYXJlLCBwaXV0dG9zdG8gY2hlIHBlciBsbyBzY29ub3NjaXV0byBjaGUgY2FudGEgbGEgbmlubmEtbmFubmEgbm9uIGZhbWlsaWFyZSAtLSBjacOyIGRvdnJlYmJlIGNvcnJpc3BvbmRlcmUgYSB0ZW1waSBkaSBmaXNzYXppb25lIG1hZ2dpcmkgcGVyIGlsIHByaW1vIHZvbHRvIHJpc3BldHRvIGFsIHNlY29uZG8uCgpMJ2FuYWxpc2kgc3RhdGlzdGljYSBlc2VndWl0YSBkYWdsaSBhdXRvcmkgw6ggdW4gdGVzdCAkdCQgZGkgU3R1ZGVudC4gTCdhcnRpY29sbyBkaSBNZWhyIGV0IGFsLiAoMjAxNikgcmlwb3J0YSB1biB2YWxvcmUgZGVsbGEgc3RhdGlzdGljYSB0ZXN0IHBhcmkgYSAkdF97MzF9ID0gMi45NiQsIHVuICRwJC12YWxvcmUgZGkgMC4wNiBlIHVuIGludGVydmFsbG8gZGkgY29uZmlkZW56YSBhbCA5NSUgcGFyaSBhIFswLjUyOSwgMC42NThdLiBMYSBkaW1lbnNpb25lIGRlbGwnZWZmZXR0bywgbWlzdXJhdGEgY29uIGlsICRkJCBkaSBDb2hlbiwgw6ggcGFyaSBhIDAuNTIuCgojIyBDb25jbHVzaW9uaQoKTWVociBlIGFsLiAoMjAxNikgcmlwb3J0YW5vIGNoZSBpIGJhbWJpbmkgZGkgY2lucXVlIG1lc2kgZGlyaWdvbm8gaW4gbW9kbyBwcmVmZXJlbnppYWxlIGxhIHByb3ByaWEgYXR0ZW56aW9uZSB2ZXJzbyB1biBhZHVsdG8gc2Nvbm9zY2l1dG8gY2hlIGNhbnRhIHVuYSBtZWxvZGlhIGZhbWlsaWFyZSBwaXV0dG9zdG8gY2hlIHZlcnNvIHVuIGFkdWx0byBzY29ub3NjaXV0byBjaGUgY2FudGEgdW5hIG1lbG9kaWEgc2ltaWxlLCBtYSBzY29ub3NjaXV0YS4gUXVlc3RpIHJpc3VsdGF0aSBzb25vIHN0YXRpIHRyb3ZhdGkgcXVhbmRvIGxhIGZhbWlsaWFyaXp6YXppb25lIGNvbiBsYSBuaW5uYS1uYW5uYSB0YXJnZXQgdmVuaXZhIGNyZWF0YSBtZWRpYW50ZSBsJ2ludGVyYXppb25lIHRyYSBpbCBiYW1iaW5vIGUgdW4gYWR1bHRvIGNoZSBmYWNldmEgcGFydGUgZGVsbCdhbWJpZW50ZSBkb21lc3RpY28uIEwnYXR0ZW56aW9uZSBkZWkgYmFtYmluaSwgaW52ZWNlLCBub24gdmVuaXZhIG1vZHVsYXRhIGRhbGxhIGZhbWlsaWFyaXTDoCBjb24gbGEgbWVsb2RpYSBuZWwgY2FzbyBpbiBjdWkgbGEgbWVsb2RpYSBpbiBxdWVzdGlvbmUgZm9zc2Ugc3RhdGEgcHJlc2VudGF0YSBpbiBwcmVjZWRlbnphIGFsIGJhbWJpbm8gaW4gdW4gbW9kbyBkaXZlcnNvLCBvdnZlcm8gZXNzZW5kbyBwcm9kb3R0YSBkYSB1biBnaW9jYXR0b2xvLCBvIGRhIHVuIGFkdWx0byBjaGUgaWwgYmFtYmlubyBjb25vc2NldmEgcG9jby4gSW4gYmFzZSBhIHRhbGkgcmlzdWx0YXRpLCBNZWhyIGUgYWwuICgyMDE2KSBjb25jbHVkb25vIGNoZSBsZSBtZWxvZGllIHByb2RvdHRlIG5lbGwnYW1iaWVudGUgZG9tZXN0aWNvLCBuZWxsJ2ludGVyYXppb25lIHRyYSBpIGJhbWJpbmkgZSBnbGkgYWR1bHRpLCBzb25vIGRvdGF0ZSBkaSB1biBwYXJ0aWNvbGFyZSBzaWduaWZpY2F0byBzb2NpYWxlIHBlciBpIGJhbWJpbmkuCgojIFNjb3BvIGRlbCBwcmVzZW50ZSBwcm9nZXR0bwoKTCdhbmFsaXNpIGRlaSBkYXRpIGRlc2NyaXR0YSBxdWkgZGkgc2VndWl0byBoYSBsbyBzY29wbyBkaSByZXBsaWNhcmUgYWxjdW5pIGRlaSByaXN1bHRhdGkgcmlwb3J0YXRpIGRhIE1laHIgZXQgYWwuICgyMDE2KSB1dGlsaXp6YW5kbyBpIGRhdGkgcmVzaSBkaXNwb25pYmlsaSBkYWdsaSBhdXRvcmkuIExlIHN0ZXNzZSBhbmFsaXNpIHN0YXRpc3RpY2hlIHZlcnJhbm5vIGVzZWd1aXRlIHVzYW5kbyBkdWUgbWV0b2RpIGRpdmVyc2k6IGwnYXBwcm9jY2lvIGZyZXF1ZW50aXN0YSAocXVlbGxvIHVzYXRvIG5lbGwnYXJ0aWNvbG8pIGUgbCdhcHByb2NjaW8gYmF5ZXNpYW5vLgoKIyBBbmFsaXNpIGRlaSBkYXRpCgpQZXIgcmVwbGljYXJlIGkgcmlzdWx0YXRpIHJpcG9ydGF0aSBkYSAgTWVociBldCBhbC4gKDIwMTYpLCBpbml6aWFtbyBhIGxlZ2dlcmUgaW4gUiBpIGRhdGkgY29udGVudXRpIG5lbCBmaWxlIGBNZWhyU29uZ1NwZWxrZV9leHBfMS5jc3ZgLiBRdWVzdG8gcmlzdWx0YXRvIHNpIG90dGllbmUgdXRpbGl6emFuZG8gbGEgZnVuemlvbmUgYGltcG9ydCgpYCBjb250ZW51dGEgbmVsIHBhY2NoZXR0byBgcmlvYC4gVXRpbGl6emlhbW8gYW5jaGUgbGUgZnVuemlvbmFsaXTDoCBkZWkgcGFjY2hldHRpIGB0aWR5dmVyc2VgIHBlciBtYW5pcG9sYXJlIGkgZGF0aSBlIGNyZWFyZSBncmFmaWNpLgoKRG9wbyBhdmVyZSBjYW1iaWF0byBsYSBjYXJ0ZWxsYSBkaSBsYXZvcm8gaW4gUlN0dWRpbywgY2FyaWNoaWFtbyBpIHBhY2NoZXR0aSBjaGUgdmVycmFubm8gdXRpbGl6emF0aSBtZWRpYW50ZSBsZSBzZWd1ZW50aSBpc3RydXppb25pOgoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyh7CiAgbGlicmFyeSgiaGVyZSIpCiAgbGlicmFyeSgidGlkeXZlcnNlIikKICBsaWJyYXJ5KCJwYXRjaHdvcmsiKQogIGxpYnJhcnkoImJheWVzcGxvdCIpCn0pICAKCnRoZW1lX3NldChiYXllc3Bsb3Q6OnRoZW1lX2RlZmF1bHQoYmFzZV9zaXplID0gMTIpKQpiYXllc3Bsb3Q6OmNvbG9yX3NjaGVtZV9zZXQoImJyaWdodGJsdWUiKSAKCm9wdGlvbnMoCiAgZGlnaXRzID0gMywKICB3aWR0aCA9IDY4LAogIHN0ciA9IHN0ck9wdGlvbnMoc3RyaWN0LndpZHRoID0gImN1dCIpLAogIGNyYXlvbi5lbmFibGVkID0gVFJVRQopCgprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgY29tbWVudCA9ICIjPiIsCiAgY29sbGFwc2UgPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UsCiAgZXJyb3IgPSBGQUxTRSwKICB3aWR0aCA9IDY4LAogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLAogIGZpZy53aWR0aCA9IDYsCiAgZmlnLmFzcCA9IDAuNjE4LCAjIDEgLyBwaGkKICBmaWcuc2hvdyA9ICJob2xkIiwKICBkcGkgPSAzMDAsCiAgZmlnLnBvcyA9ICJoIiwKICBjYWNoZS5leHRyYSA9IGtuaXRyOjpyYW5kX3NlZWQsCiAgdGlkeS5vcHRzID0gbGlzdCh3aWR0aC5jdXRvZmYgPSA3MCksCiAgdGlkeSA9ICJzdHlsZXIiCikKYGBgCgpgYGB7cn0KbWVociA8LSByaW86OmltcG9ydCgiTWVoclNvbmdTcGVsa2VfZXhwXzEuY3N2IikKYGBgCgpJIG5vbWkgZGVsbGUgY29sb25uZSBkZWxsJ29nZ2V0dG8gYG1laHJgIHZlbmdvbm8gcmVzdGl0dWl0aSB1c2FuZG8gbGEgZnVuemlvbmUgYG5hbWVzKClgIGNoZSBwcmVuZGUgY29tZSBhcmdvbWVudG8gaWwgbm9tZSBkZWwgZGF0YS5mcmFtZToKCmBgYHtyIGV2YWw9RkFMU0V9Cm5hbWVzKG1laHIpCmBgYAoKQ29uc2lkZXJpYW1vIGxhIHZhcmlhYmlsZSBgZXhwMWA6CgpgYGB7cn0KdW5pcXVlKG1laHIkZXhwMSkKYGBgCgpRdWFuZG8gYGV4cDFgIGFzc3VtZSBpbCB2YWxvcmUgMSwgaSBkYXRpIGFwcGFydGVuZ29ubyBhbCBwcmltbyBlc3BlcmltZW50bywgcXVlbGxvIGRpIGludGVyZXNzZSBxdWkuIFBlciBzZWxlemlvbmFyZSBpIGRhdGkgZGVsIHByaW1vIGVzcGVyaW1lbnRvIHVzaWFtbyBsYSBmdW56aW9uZSBgZmlsdGVyKClgOgoKYGBge3J9CmRmX2V4cDEgPC0gbWVociAlPiUgCiAgZHBseXI6OmZpbHRlcihleHAxID09IDEpCmBgYAoKTCdpc3RydXppb25lIHByZWNlZGVudGUgZGljZSBjaGUgbCdvZ2dldHRvIGBtZWhyYCAoY2hlIMOoIHVuIERhdGFGcmFtZSkgdmllbmUgcGFzc2F0byBhbGxhIGZ1bnppb25lIGBmaWx0ZXIoKWAgY29udGVudXRhIG5lbCBwYWNjaGV0dG8gYGRwbHlyYC4gTCdhcmdvbWVudG8gcGFzc2F0byBhIGBmaWx0ZXIoKWAgaXN0cnVpc2NlIFIgYSBzZWxlemlvbmFyZSBzb2xvIGxlIHJpZ2hlIGRlbCBkYXRhLmZyYW1lIGBtZWhyYCBuZWxsZSBxdWFsaSBsYSBjb2xvbm5hIGBleHBgIGhhIHZhbG9yZSAxLiAgSWwgc290dG9pbnNpZW1lIGRlbGxlIHJpZ2hlIHNlbGV6aW9uYXRlIGNvcnJpc3BvbmUgYWxsZSBvc3NlcnZhemlvbmkgY2hlIGZhbm5vIHBhcnRlIGRlbCBwcmltbyBlc3BlcmltZW50by4gTCdvcGVyYXRvcmUgZGkgYXR0cmlidXppb25lIGA8LWAgYXNzZWduYSBhbCByaXN1bHRhdG8gY2hlIGFiYmlhbW8gb3R0ZW51dG8gKG92dmVybywgYWkgZGF0aSBkZWwgcHJpbW8gZXNwZXJpbWVudG8pIGlsIG5vbWUgYGRmX2V4cDFgLgoKTGEgdmFyaWFiaWxlIGBUZXN0X1Byb3BvcnRpb25fR2F6ZV90b19TaW5nZXJgIGNvcnJpc3BvbmRlIGFsIHRlbXBvIGRpIGZpc3NhemlvbmUgZGVsbG8gc2d1YXJkbyAoZXNwcmVzc28gbmVpIHRlcm1pbmkgZGkgdW5hIHByb3Bvcnppb25lKS4gQ29zdHJ1aWFtbyB1biBpc3RvZ3JhbW1hOgoKYGBge3J9CnRpYmJsZSh5ID0gZGZfZXhwMSRUZXN0X1Byb3BvcnRpb25fR2F6ZV90b19TaW5nZXIpICU+JSAKZ2dwbG90KGFlcyh5KSkgKwogIGdlb21faGlzdG9ncmFtKAogICAgYWVzKHkgPSAuLmRlbnNpdHkuLikKICApCmBgYAoKUGnDuSB1dGlsZSDDqCB1bmEgc3RpbWEgZGVsbGEgZGVuc2l0w6AgZGVsbGEgZnJlcXVlbnphIGRlaSBkYXRpOgoKYGBge3J9CnRpYmJsZSh5ID0gZGZfZXhwMSRUZXN0X1Byb3BvcnRpb25fR2F6ZV90b19TaW5nZXIpICU+JSAKZ2dwbG90KGFlcyh5KSkgKwogIGdlb21fZGVuc2l0eSgpCmBgYAoKTWVkaWEgZSBkZXZpYXppb25lIHN0YW5kYXJkIGRlbGxlIHByb3Bvcnppb25pIGRpIHRlbXBvIHRyYXNjb3JzbyBhIGZpc3NhcmUgaWwgdm9sdG8gdGFyZ2V0IChzY29ub3NjaXV0byBjaGUgY2FudGEgbGEgbmlubmEtbmFubmEgZmFtaWxpYXJlKSBzaSBvdHRlbmdvbm8gbmVsIG1vZG8gc2VndWVudGU6CgpgYGB7cn0KZGZfZXhwMSAlPiUgCiAgc3VtbWFyaXNlKAogICAgcCA9IG1lYW4oVGVzdF9Qcm9wb3J0aW9uX0dhemVfdG9fU2luZ2VyKSwKICAgIHN0ZCA9IHNkKFRlc3RfUHJvcG9ydGlvbl9HYXplX3RvX1NpbmdlcikKICApCmBgYAoKIyMgQXBwcm9jY2lvIGZyZXF1ZW50aXN0YQoKIyMjIFRlc3QgJHQkIGRpIFN0dWRlbnQgcGVyIHVuIHNvbG8gY2FtcGlvbmUKClV0aWxpenppYW1vIG9yYSBsJ2FwcHJvY2NpbyBmcmVxdWVudGlzdGEgcGVyIGZhcmUgaW5mZXJlbnphIHN1ICRcbXUkLCBvdnZlcm8gc3VsbGEgcHJvcG9yemlvbmUgbWVkaWEgZGVsIHRlbXBvIGRpIGZpc3NhemlvbmUgcml2b2x0byBhbGxvIHNjb25vc2NpdXRvIHRhcmdldCwgcGl1dHRvc3RvIGNoZSB2ZXJzbyBsbyBzY29ub3NjaXV0byBjaGUgY2FudGEgdW5hIG5pbm5hLW5hbm5hIGlnbm90YSBhbCBiYW1iaW5vLiAKCkwnaXBvdGVzaSBudWxsYSDDqCAKCiQkCkhfMDogXG11ID0gMC41LgokJAoKU2Ugbm9uIHZpIMOoIGFsY3VuYSBwcmVmZXJlbnphLCBsYSB2YXJpYWJpbGUgYFRlc3RfUHJvcG9ydGlvbl9HYXplX3RvX1NpbmdlcmAgZG92cmViYmUgYXNzdW1lcmUgaWwgdmFsb3JlIDAuNS4gU2UgaW52ZWNlIGkgYmFtYmluaSBwcmVmZXJpc2Nvbm8gbGEgbWVsb2RpYSBmYW1pbGlhcmUsIGlsIHZhbG9yZSBtZWRpbyBkaSBgVGVzdF9Qcm9wb3J0aW9uX0dhemVfdG9fU2luZ2VyYCBkb3ZyZWJiZSBlc3NlcmUgbWFnZ2lvcmUgZGkgMC41OyBzZSBpIGJhbWJpbmkgcHJlZmVyaXNjb25vIGxhIG1lbG9kaWEgc2Nvbm9zY2l1dGEsIGlsIHZhbG9yZSBtZWRpbyBkaSBgVGVzdF9Qcm9wb3J0aW9uX0dhemVfdG9fU2luZ2VyYCBkb3ZyZWJiZSBlc3NlcmUgbWlub3JlIGRpIDAuNS4gCgpJbml6aWFtbyBhZCBlc2FtaW5hcmUgbGEgZGlzdHJpYnV6aW9uZSBkZWkgZGF0aS4gVXNpYW1vIGlsIGRpYWdyYW1tYSBxdWFudGlsZS1xdWFudGlsZSBwZXIgdmVyaWZpY2FyZSBsJ2lwb3Rlc2kgZGkgZ2F1c3NpYW5pdMOgIChuZWNlc3NhcmlhIHBlciBlc2VndWlyZSBpbCB0ZXN0IHN0YXRpc3RpY28gcmlwb3J0YXRvIGRhZ2xpIGF1dG9yaSk6CgpgYGB7cn0KdGliYmxlKHkgPSBkZl9leHAxJFRlc3RfUHJvcG9ydGlvbl9HYXplX3RvX1NpbmdlcikgJT4lIAogIGdncGxvdChhZXMoc2FtcGxlID0geSkpICsKICBzdGF0X3FxKCkgKyAKICBzdGF0X3FxX2xpbmUoKQpgYGAKCkRhdG8gY2hlIGwnYXNzdW56aW9uZSBkaSBnYXVzc2lhbml0w6Agw6ggcmFnaW9uZXZvbGUsIHByb2NlZGlhbW8gZXNlZ3VlbmRvIGlsIHRlc3QgJHQkIGRpIFN0dWRlbnQuIExhIHByb3Bvcnppb25lIGRlbCBsb29raW5nLXRpbWUgZGlyZXR0YSBhbGxvIHNjb25vc2NpdXRvIGNoZSBjYW50YSBsYSBtZWxvZGlhIGZhbWlsaWFyZSDDqAoKYGBge3J9Cm0gPC0gbWVhbihkZl9leHAxJFRlc3RfUHJvcG9ydGlvbl9HYXplX3RvX1NpbmdlcikKbQpgYGAKCnBhcmkgYSBgciByb3VuZChtLCAyKWAuIEFiaWFtbyB0cm92YXRvIHRhbGUgdmFsb3JlIHVzYW5kbyBsYSBmdW56aW9uZSBgYGBtZWFuKClgYGAgY2hlIHByZW5kZSwgY29tZSBhcmdvbWVudG8sIGlsIHZldHRvcmUgY2hlIGNvbnRpZW5lIGxhIHByb3Bvcnppb25lIGRlbCBsb29raW5nLXRpbWUgZGlyZXR0YSBhbGxvIHNjb25vc2NpdXRvIGNoZSBjYW50YSBsYSBtZWxvZGlhIGZhbWlsaWFyZSBwZXIgY2lhc2N1biBiYW1iaW5vIG5lbCBwcmltbyBlc3BlcmltZW50by4gVXRpbGl6emlhbW8gbGEgc2ludGFzc2kgYCRgIHBlciBlc3RyYXJyZSBkYWwgRGF0YUZyYW1lIGBkZl9leHAxYCBsYSBjb2xvbm5hIGRpIGRhdGkgYFRlc3RfUHJvcG9ydGlvbl9HYXplX3RvX1NpbmdlcmAuIAoKTCdlcnJvcmUgc3RhbmRhcmQgZGVsbGEgbWVkaWEgw6ggCgokJApcc2lnbWFfe1xiYXJ7eX19ID0gXGZyYWN7XHNpZ21hfXtcc3FydHtufX0KJCQKb3Z2ZXJvCgpgYGB7cn0Kc2UgPC0gc2QoZGZfZXhwMSRUZXN0X1Byb3BvcnRpb25fR2F6ZV90b19TaW5nZXIpIC8gc3FydChsZW5ndGgoZGZfZXhwMSRUZXN0X1Byb3BvcnRpb25fR2F6ZV90b19TaW5nZXIpKQpzZQpgYGAKCkxhIGZ1bnppb25lIGBsZW5ndGgoKWAgcml0b3JuYSBpbCBudW1lcm8gZGkgZWxlbWVudGkgZGkgdW4gdmV0dG9yZSBvdnZlcm8sIG5lbCBub3N0cm8gY2FzbywgbCdhbXBpZXp6YSBkZWwgY2FtcGlvbmUuCgpBcHBsaWNoaWFtbyBvcmEgbGEgZm9ybXVsYSBwZXIgaWwgY2FsY29sbyBkZWxsYSBzdGF0aXN0aWNhICpUKiwgb3Z2ZXJvCgokJApUID0gXGZyYWN7XGJhcnt5fSAtIFxtdV8wfXtcaGF0e1xzaWdtYX1fe1xiYXJ7eX19fSA9IFxmcmFjezAuNTkgLSAwLjUwfXswLjAzMn0gPSAyLjk2CiQkCgpvdnZlcm8KCmBgYHtyfQpUIDwtIChtIC0gMC41KSAvIHNlClQKYGBgCgpJIGdyYWRpIGRpIGxpYmVydMOgIHNvbm86CgpgYGB7cn0KZG9mIDwtIGxlbmd0aChkZl9leHAxJFRlc3RfUHJvcG9ydGlvbl9HYXplX3RvX1NpbmdlcikgLSAxCmRvZgpgYGAKClBlciB1biB0ZXN0IGJpZGlyZXppb25hbGUsIGlsICRwJC12YWxvcmUgZGl2ZW50YQoKYGBge3J9CnJvdW5kKDIgKiAoMSAtIHB0KFQsIGRvZikpLCAzKQpgYGAKCk5lbGwnaXN0cnV6aW9uZSBwcmVjZWRlbnRlIGFiYmlhbW8gY2FsY29sYXRvIGwnYXJlYSBzb3R0ZXNhIGFsbGEgZGl0cmlidXppb25lICR0X3szMX0kIG5lbGwnaW50ZXJ2YWxsbyAkWzIuOTYwLCBcaW5mdHldJCBlIGwnYWJiaWFtbyBtb2x0aXBsaWNhdGEgcGVyIDIuICBQZXIgdHJvdmFyZSBsJ2FyZWEgbmVsbCdpbnRlcnZhbGxvICRbMi45NjAsIFxpbmZ0eV0kLCBhYmJpYW1vIGNhbGNvbGF0byBpbCB2YWxvcmUgZGVsbGEgZnVuemlvbmUgZGkgcmlwYXJ0aXppb25lIGluIGNvcnJpc3BvbmRlbnphIGRlbCB2YWxvcmUgMi45NjAgKG92dmVybyBsJ2FyZWEgbmVsbCdpbnRlcnZhbGxvICRbLVxpbmZ0eSwgMi45NjBdJCkgZSBhYmJpYW1vIHNvdHRyYXR0byB0YWxlIHZhbG9yZSBkYSAxLjAuIAoKR2xpIHN0ZXNzaSByaXN1bHRhdGksIGNoZSBjb2luY2lkb25vIGNvbiBxdWVsbGkgdHJvdmF0aSBzb3ByYSBlIGNvbiBxdWVsbGkgcmlwb3J0YXRpIGRhZ2xpIGF1dG9yaSwgc2kgcG9zc29ubyBmYWNpbG1lbnRlIG90dGVuZXJlIHVzYW5kbyBsYSBmdW56aW9uZSBgdC50ZXN0KClgCgpgYGB7cn0KdC50ZXN0KGRmX2V4cDEkVGVzdF9Qcm9wb3J0aW9uX0dhemVfdG9fU2luZ2VyLCBtdSA9IDAuNSkKYGBgCgpMJ2ludGVydmFsbG8gZGkgY29uZmlkZW56YSBhbCA5NSUgc2kgY2FsY29sYSBjb21lCgokJApcdGV4dHtzdGltYSBkZWwgcGFyYW1ldHJvfSBccG0gdCBcdGltZXMgXHRleHR7ZXJyb3JlIHN0YW5kYXJkfQokJApOZWwgY2FzbyBwcmVzZW50ZSwgYWJiaWFtbzoKCmBgYHtyfQpyb3VuZChtICsgYygtMSwgMSkgKiBxdCgwLjk3NSwgZG9mKSAqIHNlLCAzKQpgYGAKClRhbGUgcmlzdWx0YXRvIHJpcHJvZHVjZSBxdWVsbG8gcmlwb3J0YXRvIGRhIE1laHIgZXQgYWwuICgyMDE2KS4KClVuYSBzdGltYSBkZWxsYSBkaW1lbnNpb25lIGRlbGwnZWZmZXR0byBzaSBvdHRpZW5lIGNvbWUgaWwgcmFwcG9ydG8gdHJhIGxhIGRpZmZlcmVuemEgdHJhIGxlIG1lZGllIChpbiBxdWVzdG8gY2FzbywgcHJvcG9yemlvbmkpIGUgbGEgcmVsYXRpdmEgZGV2aWF6aW9uZSBzdGFuZGFyZDoKCmBgYHtyfQpyb3VuZCgKICAobSAtIDAuNSkgLyBzZChkZl9leHAxJFRlc3RfUHJvcG9ydGlvbl9HYXplX3RvX1NpbmdlciksCiAgMwopCmBgYAoKQW5jaGUgcXVlc3RvIHJpc3VsdGF0byBjb2luY2lkZSBjb24gaWwgdmFsb3JlIHJpcG9ydGF0byBkYWdsaSBhdXRvcmkuCgoKIyMgQW5hbGlzaSBCYXllc2lhbmEKCkNpIHBvbmlhbW8gb3JhIGlsIHByb2JsZW1hIGRpIHJpcGV0ZXJlIGxlIGFuYWxpc2kgc3RhdGljaGUgcHJlY2VkZW50aSB1dGlsaXp6YW5kbyBsJ2FwcHJvY2NpbyBiYXllc2lhbm8uIENhcmljaGlhbW8gaSBwYWNjaGV0dGkgbmVjZXNzYXJpOgoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyh7CiAgbGlicmFyeSgiYnJtcyIpCiAgbGlicmFyeSgicnN0YW4iKQogIGxpYnJhcnkoImNtZHN0YW5yIikKICBsaWJyYXJ5KCJwb3N0ZXJpb3IiKQogIGxpYnJhcnkoImxvbyIpCn0pCgpyc3Rhbl9vcHRpb25zKGF1dG9fd3JpdGUgPSBUUlVFKSAjIGF2b2lkIHJlY29tcGlsYXRpb24gb2YgbW9kZWxzCm9wdGlvbnMobWMuY29yZXMgPSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKSkgIyBwYXJhbGxlbGl6ZSBhY3Jvc3MgYWxsIENQVXMKU3lzLnNldGVudihMT0NBTF9DUFBGTEFHUyA9ICItbWFyY2g9bmF0aXZlIikgIyBpbXByb3ZlIGV4ZWN1dGlvbiB0aW1lCnJzdGFuX29wdGlvbnMoYXV0b193cml0ZSA9IFRSVUUpICMgYXZvaWQgcmVjb21waWxhdGlvbiBvZiBtb2RlbHMKb3B0aW9ucyhtYy5jb3JlcyA9IHBhcmFsbGVsOjpkZXRlY3RDb3JlcygpKSAjIHBhcmFsbGVsaXplIGFjcm9zcyBhbGwgQ1BVcwpTeXMuc2V0ZW52KExPQ0FMX0NQUEZMQUdTID0gIi1tYXJjaD1uYXRpdmUiKSAjIGltcHJvdmUgZXhlY3V0aW9uIHRpbWUKYGBgCgpJIGRhdGkgc29ubyBpIHNlZ3VlbnRpOgoKYGBge3J9CnkgPC0gc29ydChkZl9leHAxJFRlc3RfUHJvcG9ydGlvbl9HYXplX3RvX1NpbmdlcikKeQpgYGAKCkNvbnNpZGVyZXJlbW8gJHkkIChjb3PDrCBjb21lIGhhbm5vIGZhdHRvIGdsaSBhdXRvcmkpIGNvbWUgdW5hIHZhcmlhYmlsZSBjb250aW51YSBwZXIgbGEgcXVhbGUgw6ggc2Vuc2F0byBhc3N1bWVyZSB1biBtZWNjYW5pc21vIGdlbmVyYXRvcmUgZGVpIGRhdGkgZ2F1c3NpYW5vIGRpIG1lZGlhIGUgZGV2aWF6aW9uZSBzdGFuZGFyZCBpZ25vdGUuIEwnaW5mZXJlbnphIHJpZ3VhcmRhIGlsIHBhcmFtZXRybyAkXG11JCBkaSB0YWxlIGRpc3RyaWJ1emlvbmUgZ2F1c3NpYW5hLgoKIyMjIEZ1bnppb25lIGBicm0oKWAKClV0aWxpenphbmRvIGRlbGxlIGRpc3RyaWJ1emlvbmkgYSBwcmlvcmkgcGVyIGkgcGFyYW1ldHJpIGRlYm9sbWVudGUgaW5mb3JtYXRpdmUsIGZhY2NpYW1vIGluZmVyZW56YSB1dGlsaXp6YW5kbyBsYSBmdW56aW9uZSBgYnJtKClgIGRlbCBwYWNjaGV0dG8gYGJybXNgOgoKYGBge3J9CmZpdCA8LSBicm0oCiAgZGF0YSA9IGRmX2V4cDEsIAogIGZhbWlseSA9IGdhdXNzaWFuKCksCiAgVGVzdF9Qcm9wb3J0aW9uX0dhemVfdG9fU2luZ2VyIH4gMSwKICBwcmlvciA9IGMoCiAgICBwcmlvcihub3JtYWwoMCwgMi4wKSwgY2xhc3MgPSBJbnRlcmNlcHQpLAogICAgcHJpb3IoY2F1Y2h5KDAsIDIuMCksIGNsYXNzID0gc2lnbWEpCiAgKSwKICBpdGVyID0gNDAwMCwgCiAgcmVmcmVzaCA9IDAsIAogIGNoYWlucyA9IDQsCiAgYmFja2VuZCA9ICJjbWRzdGFuciIKKQpgYGAKCkxlIHN0aW1lIGEgcG9zdGVyaW9yaSBkZWkgcGFyYW1ldHJpIHNpIHJlY3VwZXJhbm8gbmVsIG1vZG8gc2VndWVudGU6CgpgYGB7cn0KZml4ZWYoZml0KQpgYGAKCk5lbGwnb3V0cHV0LCBgRXN0aW1hdGVgIGNvcnJpc3BvbmRlIGFsbGEgc3RpbWEgZGVsbGEgbWVkaWEgYSBwb3N0ZXJpb3JpLCBtZW50cmUgYFEyLjVgIGUgYFE5Ny41YCBmb3JuaXNjb25vIGdsaSBlc3RyZW1pIGRlbGwnaW50ZXJ2YWxsbyBkaSBjcmVkaWJpbGl0w6AgYWwgOTUlLiAgSSByaXN1bHRhdGkgc29ubyBzaW1pbGkgYSBxdWVsbGkgcmlwb3J0YXRpIGRhZ2xpIGF1dG9yaS4KCiMjIyBNb2RlbGxvIGluIGxpbmd1YWdnaW8gU3RhbgoKUmlwZXRpYW1vIG9yYSBsJ2FuYWxpc2kgcHJlY2VkZW50ZSB1dGlsaXp6YW5vIHVuIG1vZGVsbG8gc2NyaXR0byBpbiBsaW5ndWFnZ2lvIFN0YW4uIElsIG1vZGVsbG8gcmlwb3J0YXRvIGRpIHNlZ3VpdG8gdmVycsOgIHNhbHZhdG8gbmVsbGEgY2FydGVsbGEgYGNvZGVgIGNvbiBpbCBub21lIGBub3JtYWxtb2RlbC5zdGFuYDoKCmBgYHtyfQptb2RlbFN0cmluZyA9ICIKZGF0YSB7CiAgaW50PGxvd2VyPTA+IE47CiAgdmVjdG9yW05dIHk7Cn0KcGFyYW1ldGVycyB7CiAgcmVhbCBtdTsKICByZWFsPGxvd2VyPTA+IHNpZ21hOwp9Cm1vZGVsIHsKICBtdSB+IG5vcm1hbCgwLjUsIDAuNSk7CiAgc2lnbWEgfiBjYXVjaHkoMCwgMSk7CiAgeSB+IG5vcm1hbChtdSwgc2lnbWEpOwp9CiIKd3JpdGVMaW5lcyhtb2RlbFN0cmluZywgY29uID0gImNvZGUvbm9ybWFsbW9kZWwuc3RhbiIpCmBgYAoKU2lzdGVtaWFtbyBpIGRhdGkgbmVsIGZvcm1hdG8gYXBwcm9wcmlhdG8gcGVyIFN0YW46CgpgYGB7cn0KZGF0YV9saXN0IDwtIGxpc3QoCiAgTiA9IGxlbmd0aChkZl9leHAxJFRlc3RfUHJvcG9ydGlvbl9HYXplX3RvX1NpbmdlciksCiAgeSA9IGRmX2V4cDEkVGVzdF9Qcm9wb3J0aW9uX0dhemVfdG9fU2luZ2VyCikKZGF0YV9saXN0CmBgYAoKTGVnZ2lhbW8gaWwgZmlsZSBpbiBjdWkgYWJiaWFtbyBzYWx2YXRvIGlsIGNvZGljZSBTdGFuCgpgYGB7cn0KZmlsZSA8LSBmaWxlLnBhdGgoImNvZGUiLCAibm9ybWFsbW9kZWwuc3RhbiIpCmBgYAoKY29tcGlsaWFtbyBpbCBtb2RlbGxvCgpgYGB7cn0KbW9kIDwtIGNtZHN0YW5fbW9kZWwoZmlsZSkKYGBgCgpcbm9pbmRlbnQKZWQgZXNlZ3VpYW1vIGlsIGNhbXBpb25hbWVudG8gTUNNQzoKCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30KZml0IDwtIG1vZCRzYW1wbGUoCiAgZGF0YSA9IGRhdGFfbGlzdCwKICBpdGVyX3NhbXBsaW5nID0gNDAwMEwsCiAgaXRlcl93YXJtdXAgPSAyMDAwTCwKICBzZWVkID0gMTIzLAogIGNoYWlucyA9IDRMLAogIHBhcmFsbGVsX2NoYWlucyA9IDJMLAogIHJlZnJlc2ggPSAwLAogIHRoaW4gPSAxCikKYGBgCgpMYSBjb252ZXJnZW56YSBlIGlsICJtaXhpbmciIGRlbCBjYW1waW9uYW1hbnRvIE1DTUMgcG9zc29ubyBlc3NlcmUgY29udHJvbGxhdGUgbWVkaWFudGUgaWwgX3RyYWNlIHBsb3RfIGNoZSBtb3N0cmEgbCdhbmRhbWVudG8gZGVsbGUgc2ltdWxhemlvbmkgZSBjaSBkaWNlIHNlIHN0aWFtbyBlZmZldHRpdmFtZW50ZSB1dGlsaXp6YW5kbyB1bmEgZGlzdHJpYnV6aW9uZSBsaW1pdGU6CgpDb252ZXJ0aWFtbyBsJ29nZ2V0dG8gYGZpdGAgaW4gZm9ybWF0byBgc3RhbmZpdGAsIAoKYGBge3J9CnN0YW5maXQgPC0gcnN0YW46OnJlYWRfc3Rhbl9jc3YoZml0JG91dHB1dF9maWxlcygpKQpgYGAKCkVzYW1pbmlhbW8gaSB0cmFjZS1wbG90OgoKYGBge3J9CnN0YW5maXQgJT4lIAogIG1jbWNfdHJhY2UocGFycyA9IGMoIm11IiwgInNpZ21hIiksIHNpemUgPSAwLjEpCmBgYAoKTGEgc3RpbWEgZGVsbGEgZGlzdHJpYnV6aW9uZSBhIHBvc3RlcmlvcmkgcGVyICRcbXUkIHBlciBjaWFzY3VuYSBkZWxsZSBxdWF0dHJvIGNhdGVuZSB1c2F0ZSBwdcOyIGVzc2VyZSByYXBwcmVzZW50YXRhIGdyYWZpY2FtZW50ZSBuZWwgbW9kbyBzZWd1ZW50ZToKCmBgYHtyfQptY21jX2RlbnNfb3ZlcmxheShzdGFuZml0LCBwYXJzID0gIm11IikgKyAKICB5bGFiKCJkZW5zaXR5IikKYGBgCgpFc2FtaW5pYW1vIGxhIHN0YXRpc3RpY2EgJFxoYXR7Un0kOgoKYGBge3J9CmJheWVzcGxvdDo6cmhhdChzdGFuZml0LCBwYXJzID0gYygibXUiLCAic2lnbWEiKSkKYGBgCgpVdGlsaXp6YW5kbyBsJ29nZ2V0dG8gYHN0YW5maXRgLCBwb3NzaWFtbyByZWN1cGVyYXJlIGxhIHN0YXRpc3RpY2EgZGkgR2V3ZWtlIG5lbCBtb2RvIHNlZ3VlbnRlOgoKYGBge3J9CmZpdF9tY21jIDwtIEFzLm1jbWMubGlzdCgKICBzdGFuZml0LAogIHBhcnMgPSBjKCJtdSIsICJzaWdtYSIpCikKY29kYTo6Z2V3ZWtlLmRpYWcoZml0X21jbWMsIGZyYWMxID0gLjEsIGZyYWMyID0gLjUpIApgYGAKCkxhIHN0YXRpc3RpY2EgZGkgR2V3ZWtlIMOoIHVndWFsZSBhIHplcm8gcXVhbmRvIGxlIG1lZGllIGRlbGxlIGR1ZSBwb3J6aW9uaSBkZWxsYSAgY2F0ZW5hIGRpIE1hcmtvdiBzb25vIHVndWFsaS4gVmFsb3JpIG1hZ2dpb3JpIGRpICRcbWlkIDIgXG1pZCQgc3VnZ2VyaXNjb25vIGNoZSBsYSBjYXRlbmEgbm9uIGhhIGFuY29yYSByYWdnaXVudG8gdW5hIGRpc3RyaWJ1emlvbmUgc3RhemlvbmFyaWEuCgpMZSBzdGltZSBhIHBvc3RlcmlvcmkgZGVpIHBhcmFtZXRyaSBzaSBvdHRlbmdvbm8gY29uCgpgYGB7cn0KcyA8LSBzdW1tYXJ5KAogIHN0YW5maXQsIAogIGMoIm11IiwgInNpZ21hIiksIAogIHByb2JzID0gYygwLjAyNSwgMC41MCwgMC45NzUpLAogIHVzZV9jYWNoZSA9IFRSVUUKICApCnMkc3VtbWFyeSAgIyBhbGwgY2hhaW5lcyBtZXJnZWQKYGBgCgpJIHJpc3VsdGF0aSByZXBsaWNhbm8gcXVlbGxpIG90dGVudXRpIGluIHByZWNlZGVuemEuCgpNb2RpZmljaGlhbW8gb3JhIGlsIG1vZGVsbG8gaW5zZXJlbmRvIHVuYSBkaXN0cmlidXppb25lIGEgcHJpb3JpIHBpw7kgc2Vuc2F0YSBwZXIgaWwgcGFyYW1ldHJvICRcbXUkLiBFc3NlbmRvIHVuYSBwcm9wb3J6aW9uZSwgZGV2ZSBlc3NlcmUgdW4gbnVtZXJvIGNvbXByZXNvIHRyYSAwIGUgMS4gUGVydGFudG8sIHF1YWxlIGRpc3RyaWJ1emlvbmUgYSBwcmlvcmksIMOoIHNlbnNhdG8gdXNhcmUgdW5hIGRpc3RyaWJ1emlvbmUgQmV0YS4gVXRpbGl6emVyZW1vIHF1aSB1bmEgQmV0YSgyLDIpLCBvdnZlcm8gdW5hIGRpc3RyaWJ1emlvbmUgYSBwcmlvcmkgZGVib2xtZW50ZSBpbmZvcm1hdGl2YS4KCmBgYHtyfQptb2RlbFN0cmluZyA9ICIKZGF0YSB7CiAgaW50PGxvd2VyPTA+IE47CiAgdmVjdG9yW05dIHk7Cn0KcGFyYW1ldGVycyB7CiAgcmVhbCBtdTsKICByZWFsPGxvd2VyPTA+IHNpZ21hOwp9Cm1vZGVsIHsKICBtdSB+IGJldGEoMiwgMik7CiAgc2lnbWEgfiBjYXVjaHkoMCwgMSk7CiAgeSB+IG5vcm1hbChtdSwgc2lnbWEpOwp9CiIKd3JpdGVMaW5lcyhtb2RlbFN0cmluZywgY29uID0gImNvZGUvbm9ybWFsbW9kZWwyLnN0YW4iKQpgYGAKCkxlZ2dpYW1vIGlsIGZpbGUgaW4gY3VpIGFiYmlhbW8gc2FsdmF0byBpbCBjb2RpY2UgU3RhbgoKYGBge3J9CmZpbGUyIDwtIGZpbGUucGF0aCgiY29kZSIsICJub3JtYWxtb2RlbDIuc3RhbiIpCmBgYAoKXG5vaW5kZW50CmNvbXBpbGlhbW8gaWwgbW9kZWxsbwoKYGBge3J9Cm1vZDIgPC0gY21kc3Rhbl9tb2RlbChmaWxlMikKYGBgCgpcbm9pbmRlbnQKZWQgZXNlZ3VpYW1vIGlsIGNhbXBpb25hbWVudG8gTUNNQzoKCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30KZml0MiA8LSBtb2QyJHNhbXBsZSgKICBkYXRhID0gZGF0YV9saXN0LAogIGl0ZXJfc2FtcGxpbmcgPSA0MDAwTCwKICBpdGVyX3dhcm11cCA9IDIwMDBMLAogIHNlZWQgPSAxMjMsCiAgY2hhaW5zID0gNEwsCiAgcGFyYWxsZWxfY2hhaW5zID0gMkwsCiAgcmVmcmVzaCA9IDAsCiAgdGhpbiA9IDEKKQpgYGAKClRyb3ZpYW1vIGxlIHN0aW1lIGEgcG9zdGVyaW9yaSBkZWkgcGFyYW1ldHJpOgoKYGBge3J9CnN0YW5maXQyIDwtIHJzdGFuOjpyZWFkX3N0YW5fY3N2KGZpdDIkb3V0cHV0X2ZpbGVzKCkpCgpzIDwtIHN1bW1hcnkoCiAgc3RhbmZpdDIsIAogIGMoIm11IiwgInNpZ21hIiksIAogIHByb2JzID0gYygwLjAyNSwgMC41MCwgMC45NzUpLAogIHVzZV9jYWNoZSA9IFRSVUUKICApCnMkc3VtbWFyeSAgIyBhbGwgY2hhaW5lcyBtZXJnZWQKYGBgCgpJIHJpc3VsdGF0aSBzb25vIHF1YXNpIGlkZW50aWNpIGEgcXVlbGxpIHRyb3ZhdGkgaW4gcHJlY2VkZW56YS4KClBvc3NpYW1vIGR1bnF1ZSBjb25jbHVkZXJlLCBjb24gdW4gZ3JhZG8gZGkgY2VydGV6emEgc29nZ2V0dGl2YSBkZWwgOTUlLCBjaGUgc2lhbW8gc2ljdXJpIGNoZSBsYSBwcm9wb3J6aW9uZSBkZWwgdGVtcG8gY29tcGxlc3Npdm8gZGkgZmlzc2F6aW9uZSBkZWxsbyBzZ3VhcmRvIHZlcnNvIGxvIHNjb25vc2NpdXRvIGNoZSBjYW50YXZhIGxhIG1lbG9kaWEgZmFtaWxpYXJlIChwaXV0dG9zdG8gY2hlIHZlcnNvIGxvIHNjb25vc2NpdXRvIGNoZSBjYW50YXZhIHVuYSBuaW5uLW5hbm5hIGlnbm90YSksIMOoIGNvbXByZXNhIG5lbGwnaW50ZXJ2YWxsbyBbYHIgcm91bmQocyRzdW1tYXJ5WzEsIDRdLCAzKWAsIGByIHJvdW5kKHMkc3VtbWFyeVsxLCA2XSwgMylgXS4KCiMgQ29uZnJvbnRvIHRyYSBkdWUgZ3J1cHBpCgojIyBBcHByb2NjaW8gZnJlcXVlbnRpc3RhICh0ZXN0ICR0JCBkaSBTdHVkZW50IHBlciBjYW1waW9uaSBhcHBhaWF0aSkKCkluIHVuYSBkaXZlcnNhIGFuYWxpc2kgc3RhdGlzdGljYSwgTWVociBlIGFsLiAoMjAxNikgaGFubm8gY29uZnJvbnRhdG8gaWwgdGVtcG8gZGkgZmlzc2F6aW9uZSBkZWxsbyBzZ3VhcmRvIGRpcmV0dG8gdmVyc28gbG8gc2Nvbm9zY2l1dG8gY2hlIHNvcnJpZGUgc29sdGFudG8gZSB2ZXJzbyBsbyBzY29ub3NjaXV0byBjaGUgY2FudGEgbGEgbmlubmEtbmFubmEgZmFtaWxpYXJlLiBDaSBkb3ZyZW1tbyBhc3BldHRhcmUgdW4gdGVtcG8gZGkgZmlzc2F6aW9uZSBtYWdnaW9yZSBuZWwgc2Vjb25kbyBjYXNvIHJpc3BldHRvIGFsIHByaW1vLgoKTGEgZGlzdHJpYnV6aW9uZSBkZWkgdGVtcGkgZGkgZmlzc2F6aW9uZSBkZWxsbyBzZ3VhcmRvIG5lbGxlIGR1ZSBjb25kaXppb25pIMOoIHByZXNlbnRhdGEgbmVsIHBhbm5lbGxvIGEgZGVsbGEgRmlndXJhIDIgZGVsIGxvcm8gYXJ0aWNvbG8uIFJpcHJvZHVjaWFtbyBxdWkgc290dG8gbGEgZmlndXJhLiBJIHRlbXBpIGRpIGZpc3NhemlvbmUgZGVsbG8gc2d1YXJkbyBuZWxsZSBjb25kaXppb25pIGJhc2VsaW5lIGUgdGVzdCBjb3JyaXNwb25kb25vLCByaXNwZXR0aXZhbWVudGUsIGFsbGUgdmFyaWFiaWxpIGBgYEJhc2VsaW5lX1Byb3BvcnRpb25fR2F6ZV90b19TaW5nZXJgYGAgZSBgYGBUZXN0X1Byb3BvcnRpb25fR2F6ZV90b19TaW5nZXJgYGAuIAoKUGVyIHJlcGxpY2FyZSBsYSBGaWd1cmEgMmEgcmlwb3J0YXRhIG5lbGwnYXJ0aWNvbG8gZG9iYmlhbW8gc2lzdGVtYXJlIGkgZGF0aSBuZWwgZm9ybWF0byBgYGxvbmcnJywgb3Z2ZXJvIG5lbCBmb3JtYXRvIGluIGN1aSBhIGNpYXNjdW5hIGNvbG9ubmEgZGVsIERhdGFGcmFtZSBjb3JyaXNwb25kZSB1bmEgdmFyaWFiaWxlLiBOZWwgY2FzbyBwcmVzZW50ZSwgcG9zc2lhbW8gY3JlYXJlIHVuYSB2YXJpYWJpbGUgY2hpYW1hdGEgKmNvbmRpemlvbmUqLCBjb24gbW9kYWxpdMOgICpiYXNlbGluZSogZSAqdGVzdCosIGUgdW5hIHNlY29uZGEgdmFyaWFiaWxlLCAqeSosIGNoZSBjb3JyaXNwb25kZSBhaSB0ZW1waSBkaSBmaXNzYXppb25lIGRlbGxvIHNndWFyZG8uIFBlciBjcmVhcmUgdW4gRGF0YUZyYW1lIGNoZSBjb250aWVuZSBxdWVzdGUgZHVlIHZhcmlhYmlsaSwgcHJvY2VkaWFtbyBjb21lIHNlZ3VlLgoKYGBge3J9CmNvbmRpemlvbmUgPC0gZmFjdG9yKAogIHJlcCgKICAgIGMoImJhc2VsaW5lIiwgInRlc3QiKSwgCiAgICBlYWNoID0gbGVuZ3RoKGRmX2V4cDEkQmFzZWxpbmVfUHJvcG9ydGlvbl9HYXplX3RvX1NpbmdlcikKICAgICkKICApCnkgPC0gYyhkZl9leHAxJEJhc2VsaW5lX1Byb3BvcnRpb25fR2F6ZV90b19TaW5nZXIsIGRmX2V4cDEkVGVzdF9Qcm9wb3J0aW9uX0dhemVfdG9fU2luZ2VyKQpkZjIgPC0gZGF0YS5mcmFtZShjb25kaXppb25lLCB5KQpoZWFkKGRmMikKZGltKGRmMikKYGBgCgpJbCBkaWFncmFtbWEgYSBzY2F0b2xhIChzaW1pbGUgYSBxdWVsbG8gcmlwb3J0YXRvIG5lbGwnYXJ0aWNvbG8pIHNpIGNyZWEgY29uIGxlIHNlZ3VlbnRpIGlzdHJ1emlvbmk6CgpgYGB7cn0KcCA8LSBkZjIgJT4lCiAgZ2dwbG90KGFlcyh4ID0gY29uZGl6aW9uZSwgeSA9IHksIGZpbGwgPSBjb25kaXppb25lKSkgKwogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNykgKwogIHNjYWxlX3lfY29udGludW91cygKICAgIG5hbWUgPSAiUHJvcG9yemlvbmUgZGkgZmlzc2F6aW9uaSB2ZXJzbyBpbCBcbmNhbnRhbnRlIGRpIGNhbnpvbmUgZmFtaWxpYXJlIgogICkgKwogIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9ICJDb25kaXppb25lIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHN0YXRfc3VtbWFyeSgKICAgIGZ1bi55ID0gbWVhbiwgY29sb3VyID0gImRhcmtyZWQiLCBnZW9tID0gInBvaW50IiwKICAgIHNoYXBlID0gMTgsIHNpemUgPSA2CiAgKQpwCmBgYAoKVW5hIHJhcHByZXNlbnRhemlvbmUgcGnDuSBlZmZpY2FjZSBkZWkgZGF0aSBzaSBvdHRpZW5lIHJpcG9ydGFuZG8sIHBlciBjaWFzY3VuYSBjb25kaXppb25lLCB0dXR0ZSBsZSBzaW5nb2xlIG9zc2VydmF6aW9uaSwgaW5zaWVtZSBhbGxhIG1lZGlhbmEgZGkgY2lhc2N1biBncnVwcG86CgpgYGB7cn0KIG1laHJfc3VtbWFyeSA8LSBkZjIgJT4lCiAgZ3JvdXBfYnkoY29uZGl6aW9uZSkgJT4lCiAgc3VtbWFyaXplKAogICAgbHRfbWVhbiA9IG1lYW4oeSksCiAgICBsdF9zZCA9IHNkKHkpLAogICAgbHRfbWVkaWFuID0gbWVkaWFuKHkpCiAgKSAlPiUKICB1bmdyb3VwKCkKCmBgYAoKYGBge3J9CmRmMiAlPiUKICBnZ3Bsb3QoCiAgICBhZXMoeCA9IGNvbmRpemlvbmUsIHkgPSB5LCBjb2xvciA9IGNvbmRpemlvbmUpCiAgKSArCiAgZ2dmb3JjZTo6Z2VvbV9zaW5hKGFlcyhjb2xvciA9IGNvbmRpemlvbmUsIHNpemUgPSAzLCBhbHBoYSA9IC41KSkgKwogIGdlb21fZXJyb3JiYXIoCiAgICBhZXMoeSA9IGx0X21lZGlhbiwgeW1pbiA9IGx0X21lZGlhbiwgeW1heCA9IGx0X21lZGlhbiksCiAgICBkYXRhID0gbWVocl9zdW1tYXJ5LCB3aWR0aCA9IDAuNSwgc2l6ZSA9IDMKICApICsKICBsYWJzKAogICAgeCA9ICIiLAogICAgeSA9ICJQcm9wb3J6aW9uZSBkaSBmaXNzYXppb25pIHZlcnNvIGlsIFxuY2FudGFudGUgZGkgY2Fuem9uZSBmYW1pbGlhcmUiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgc2NhbGVfY29sb3VyX2dyZXkoc3RhcnQgPSAwLjcsIGVuZCA9IDApCmBgYAoKClVuIGNvbmZyb250byB0cmEgcXVlc3RlIGR1ZSBjb25kaXppb25pIHZpZW5lIGVmZmV0dHVhdG8gY29uIHVuIHRlc3QgJHQkIGRpIFN0dWRlbnQgcGVyIGNhbXBpb25pIGFwcGFpYXRpLiBPdnZlcm8KCmBgYHtyfQpkaWZmIDwtIGRmX2V4cDEkVGVzdF9Qcm9wb3J0aW9uX0dhemVfdG9fU2luZ2VyIC0gZGZfZXhwMSRCYXNlbGluZV9Qcm9wb3J0aW9uX0dhemVfdG9fU2luZ2VyCmRpZmYKYGBgCgpWZXJpZmljaGlhbW8gbGEgZ2F1c3NpYW5pdMOgIGRlaSBkYXRpOgoKYGBge3J9CnRpYmJsZSh5ID0gZGlmZikgJT4lIAogIGdncGxvdChhZXMoc2FtcGxlID0geSkpICsKICBzdGF0X3FxKCkgKyAKICBzdGF0X3FxX2xpbmUoKQpgYGAKTGEgbWVkaWEgZGVsbGUgZGlmZmVyZW56ZSDDqDoKYGBge3J9Cm0gPC0gbWVhbihkaWZmKQptCmBgYAoKTCdlcnJvcmUgc3RhbmRhcmQgZGVsbGUgZGlmZmVyZW56ZSDDqDoKCmBgYHtyfQpzZSA8LSBzZChkaWZmKSAvIHNxcnQobGVuZ3RoKGRpZmYpKQpzZQpgYGAKCkxhIHN0YXRpc3RpY2EgJFQkIMOoOgoKYGBge3J9ClQgPC0gKG0gLSAwKSAvIHNlClQKYGBgCgpJIGdyYWRpIGRpIGxpYmVydMOgIHNvbm86CgpgYGB7cn0KbnUgPC0gbGVuZ3RoKGRpZmYpIC0gMQpudQpgYGAKCklsIHAtdmFsb3JlIMOoOgoKYGBge3J9CjIgKiAoMSAtIHB0KFQsIG51KSkKYGBgCgpVc2FuZG8gYHQudGVzdCgpYCBvdHRlbmlhbW86CgpgYGB7cn0KdC50ZXN0KGRpZmYsIG11ID0gMCkKYGBgCgpRdWVzdGkgcmlzdWx0YXRpIHJlcGxpY2FubyBpIHZhbG9yaSByaXBvcnRhdGkgZGFnbGkgYXV0b3JpOiAkdF97MzF9JCA9IDIuNDIsICRwJCA9IDAuMjIuCgpMJ2ludGVydmFsbG8gZGkgY29uZmlkZW56YSDDqAoKYGBge3J9Cm1lYW4oZGlmZikgKyBjKC0xLCAxKSAqIHF0KC45NzUsIG51KSAqIHNlCmBgYAoKTGEgZGltZW5zaW9uZSBkZWxsJ2VmZmV0dG8gw6gKCmBgYHtyfQpkIDwtIG1lYW4oZGlmZikgLyBzZChkaWZmKQpkCmBgYAoKTGUgc3RpbWUgZGVsbCdpbnRlcnZhbGxvIGRpIGNvbmZpZGVuemEgZSBkZWxsYSBkaW1lbnNpb25lIGRlbGwnZWZmZXR0byBjb2luY2lkb25vIGNvbiBpIHZhbG9yaSByaXBvcnRhdGkgZGEgTWVociBlIGFsLiAoMjAxNikuCgojIyBBbmFsaXNpIGJheWVzaWFuYQoKRGF0byBjaGUsIG5lbCBjYXNvIGRpIGNhbXBpb25pIGFwcGFpYXRpLCBhYmJpYW1vIHVuIHVuaWNvIHZhbG9yZSBkZWxsYSB2YXJpYmlsZSBkaXBlbmRlbnRlIHBlciBjaWFzY3VuYSAiY29wcGlhIiwgbCdhbmFsaXNpIHN0YXRpc3RpY2Egw6ggc29zdGFuemlhbG1lbnRlIGlkZW50aWNhIGEgcXVlbGxhIGdpw6AgZGVzY3JpdHRhIHNvcHJhLiBJbiBxdWVzdG8gY2FzbywgbGEgdmFyaWFiaWxlIGRpcGVuZGVudGUgw6ggY2hpYW1hdGEgYGRpZmZgLgoKYGBge3J9CmRhdGEyX2xpc3QgPC0gbGlzdCgKICBOID0gbGVuZ3RoKGRpZmYpLAogIHkgPSBkaWZmCikKZGF0YTJfbGlzdApgYGAKClVzaWFtbyBudW92YW1lbnRlIGlsIG1vZGVsbG8gYG5vcm1hbG1vZGVsMi5zdGFuYCBjaGUgYWJiaWFtbyBnacOgIGNvbXBpbGF0byBpbiBwcmVjZWRlbnphIGVkIGVzZWd1aWFtbyBpbCBjYW1waW9uYW1lbnRvIE1DTUM6CgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CmZpdDMgPC0gbW9kMiRzYW1wbGUoCiAgZGF0YSA9IGRhdGEyX2xpc3QsCiAgaXRlcl9zYW1wbGluZyA9IDQwMDBMLAogIGl0ZXJfd2FybXVwID0gMjAwMEwsCiAgc2VlZCA9IDEyMywKICBjaGFpbnMgPSA0TCwKICBwYXJhbGxlbF9jaGFpbnMgPSAyTCwKICByZWZyZXNoID0gMCwKICB0aGluID0gMQopCmBgYAoKTGUgc3RpbWUgYSBwb3N0ZXJpb3JpIGRlaSBwYXJhbWV0cmkgc2kgb3R0ZW5nb25vIGNvbjoKCmBgYHtyfQpzdGFuZml0MyA8LSByc3Rhbjo6cmVhZF9zdGFuX2NzdihmaXQzJG91dHB1dF9maWxlcygpKQpgYGAKCmBgYHtyfQpzIDwtIHN1bW1hcnkoCiAgc3RhbmZpdDMsIAogIGMoIm11IiwgInNpZ21hIiksIAogIHByb2JzID0gYygwLjAyNSwgMC41MCwgMC45NzUpLAogIHVzZV9jYWNoZSA9IFRSVUUKICApCnMkc3VtbWFyeSAgIyBhbGwgY2hhaW5lcyBtZXJnZWQKYGBgCgoKSSByaXN1bHRhdGkgc29ubyBtb2x0byBzaW1pbGkgYWkgcHJlY2VkZW50aS4gCgpEYWxsJ291dHB1dCBwcmVjZWRlbnRlIHBvc3NpYW1vIG90dGVuZXJlIHVuYSBzdGltYSBkZWxsYSBkaW1lbnNpb25lIGRlbGwnZWZmZXR0bzoKCmBgYHtyfQpzJHN1bW1hcnlbMSwgMV0JLwlzJHN1bW1hcnlbMiwgMV0KYGBgCgpBbmNoZSBpbiBxdWVzdG8gY2FzbywgaWwgcmlzdWx0YXRvIMOoIHNpbWlsZSBhIHF1ZWxsbyBvdHRlbnV0byBzb3ByYS4KCiMgQ29uY2x1c2lvbmkKClV0aWxpenphbmRvIGkgZGF0aSBncmV6emkgbWVzc2kgYSBkaXNwb3NpemlvbmUgZGFnbGkgYXV0b3JpIHNpYW1vIHN0YXRpIGluIGdyYWRvIGRpIHJlcGxpY2FyZSBpIHJpc3VsdGF0aSByaXBvcnRhdGkgZGFsbCdhcnRpY29sbyBkaSBNZWhyIGUgYWwuICgyMDE2KS4gSW4gcXVlc3RhIHJlbGF6aW9uZSBjaSBzaWFtbyBmb2NhbGl6emF0aSBzdSBkdWUgcHJvYmxlbWk6IGwnaW5mZXJlbnphIHN1IHVuYSBtZWRpYSBlIGwnaW5mZXJlbnphIHN1IGR1ZSBtZWRpZSBuZWwgY2FzbyBkaSBkYXRpIGFwcGFpYXRpLiBOZWwgY2FzbyBwcmVzZW50ZSwgaSByaXN1bHRhdGkgZGVsbCdhbmFsaXNpIGJheWVzaWFuYSBzb25vIHByYXRpY2FtZW50ZSBpZGVudGljaSBhIHF1ZWxsaSBwcm9kb3R0aSBkYWxsJ2FwcHJvY2NpbyBmcmVxdWVudGlzdGEsIHNlIHZlbmdvbm8gdXNhdGUgZGlzdHJpYnV6aW9uaSBhIHByaW9yaSBkZWJvbG1lbnRlIGluZm9ybWF0aXZlLiBVdGlsaXp6YW5kbyBgZ2dwbG90KClgIHNpYW1vIGFuY2hlIHN0YXRpIGluIGdyYWRvIGRpIHJlcGxpY2FyZSB1bmEgZGVsbGUgZmlndXJlIHJpcG9ydGF0ZSBuZWxsJ2FydGljb2xvIGRpIE1laHIgZSBhbC4gKDIwMTYpLiBBYmJpYW1vIGFuY2hlIHByb3Bvc3RvIHVuYSBudW92YSB2ZXJzaW9uZSBkaSB0YWxlIGZpZ3VyYSBjaGUgc2VtYnJhIHBpw7kgaW5mb3JtYXRpdmEgZGkgcXVlbGxhIHByb3Bvc3RhIGRhZ2xpIGF1dG9yaS4KCkxlIGFuYWxpc2kgc3RhdGlzdGljaGUgZGVzY3JpdHRlIGRhIE1laHIgZSBhbC4gKDIwMTYpIHNvbm8gY29udmluY2VudGk6IGkgZGF0aSBub24gbW9zdHJhbm8gYW5vbWFsaWUgZGVnbmUgZGkgbm90YSBlIGxlIGFzc3VuemlvbmkgYWxsYSBiYXNlIGRlaSB0ZXN0IHN0YXRpc3RpY2kgc3ZvbHRpIGRhZ2xpIGF1dG9yaSAtLSBvdnZlcm8sIGxhIGdhdXNzaWFuaXTDoCBkZWkgZGF0aSAtLSBzb25vIHNlbnNhdGUuIMOIIGR1bnF1ZSBzZW5zYXRvIGNvbmNsdWRlcmUgY2hlIGxhIG11c2ljYSBzZW1icmEgcG9zc2VkZXJlIHVuIGltcG9ydGFudGUgdmFsb3JlIHNvY2lhbGUgYW5jaGUgbmVsIGNhc28gZGkgYmFtYmluaSBtb2x0byBwaWNjb2xpLgoKIyBSaWZlcmltZW50aSBiaWJsaW9ncmFmaWNpCgpNZWhyLCBTLiBBLiwgU29uZywgTC4gQS4sICYgU3BlbGtlLCBFLiBTLiAoMjAxNikuIEZvciA1LW1vbnRoLW9sZCBpbmZhbnRzLCBtZWxvZGllcyBhcmUgc29jaWFsLiAqUHN5Y2hvbG9naWNhbCBTY2llbmNlKiwgKjI3Kig0KSwgNDg2LTUwMS4KCiMjIEluZm9ybWF6aW9uaSBzdWxsYSBzZXNzaW9uZSBkaSBsYXZvcm8gey19IAoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgo=